Mkyong-中文博客翻译-一-

Mkyong 中文博客翻译(一)

原文:Mkyong

协议:CC BY-NC-SA 4.0

从 JSF 页面向后台 bean 传递参数的 4 种方法

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/

据我所知,从 JSF 页面向后台 bean 传递参数值有 4 种方式:

  1. 方法表达式(JSF 2.0)
  2. 问:我的钱
  3. f:属性
  4. f:setPropertyActionListener

让我们一个一个地看例子:

1.方法表达式

从 JSF 2.0 开始,允许在方法表达式中像这样传递参数值 #{bean.method(param)}

JSF 页……

 <h:commandButton action="#{user.editAction(delete)}" /> 

背豆……

 @ManagedBean(name="user")
@SessionScoped
public class UserBean{

	public String editAction(String id) {
	  //id = "delete"
	}

} 

Note
If you are deploy JSF application in servlet container like Tomcat, make sure you include the “el-impl-2.2.jar” properly. For detail, please read this article – JSF 2.0 method expression caused error in Tomcat. ## 第二,我的钱

通过f:param标签传递参数值,并通过 backing bean 中的请求参数取回。

JSF 页……

 <h:commandButton action="#{user.editAction}">
	<f:param name="action" value="delete" />
</h:commandButton> 

背豆……

 @ManagedBean(name="user")
@SessionScoped
public class UserBean{

	public String editAction() {

	  Map<String,String> params = 
                FacesContext.getExternalContext().getRequestParameterMap();
	  String action = params.get("action");
          //...

	}

} 

点击这里查看完整的 f:param 示例

3.女:属性

通过f:atribute标签传递参数值,并通过 backing bean 中的动作监听器获取它。

JSF 页……

 <h:commandButton action="#{user.editAction}" actionListener="#{user.attrListener}"> 
	<f:attribute name="action" value="delete" />
</h:commandButton> 

背豆……

 @ManagedBean(name="user")
@SessionScoped
public class UserBean{

  String action;

  //action listener event
  public void attrListener(ActionEvent event){

	action = (String)event.getComponent().getAttributes().get("action");

  }

  public String editAction() {
	//...
  }	

} 

在这里可以看到完整的 f:attribute 示例

4. f:setPropertyActionListener

通过f:setPropertyActionListener标签传递参数值,它会将值直接设置到您的后台 bean 属性中。

JSF 页……

 <h:commandButton action="#{user.editAction}" >
    <f:setPropertyActionListener target="#{user.action}" value="delete" />
</h:commandButton> 

背豆……

 @ManagedBean(name="user")
@SessionScoped
public class UserBean{

	public String action;

	public void setAction(String action) {
		this.action = action;
	}

	public String editAction() {
	   //now action property contains "delete"
	}	

} 

请在此查看完整的 f:setPropertyActionListener 示例

P.S 请分享你的想法,如果你有任何其他方法:)

backing bean jsf2 parameter

404 错误代码在 Spring MVC 中不起作用

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/404-error-code-is-not-working-in-spring-mvc/

问题

在 Spring MVC 应用程序中,404 错误代码配置正确。请参见下面的 web.xml 片段。

文件:web.xml

 <web-app ...>

  <servlet>
  	<servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
 	<servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

  //...
  <error-page>
	<error-code>404</error-code>
	<location>/WEB-INF/pages/404.htm</location>
  </error-page>

</web-app> 

然而,当用户访问任何不存在的资源时,它将显示一个空白页面,而不是 404.htm

解决办法

404 错误代码配置正确,但会导致“”。“ servlet 容器和 Spring 的“ DispatcherServlet ”之间的扩展处理冲突。要解决这个问题,请尝试将 404.htm 更改为其他文件扩展名,例如 404.jsp。

文件:web.xml

 <web-app ...>

  <servlet>
  	<servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
 	<servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

  //...
  <error-page>
	<error-code>404</error-code>
	<location>/WEB-INF/pages/404.jsp</location>
  </error-page>

</web-app> 

现在,当用户访问任何不存在的资源时,它会转到 404.jsp 页面。

404 spring mvc (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225092406/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

从事件监听器-JSF 访问受管 bean

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/access-a-managed-bean-from-event-listener-jsf/

问题

JSF 事件侦听器类如何访问另一个受管 bean?请参见下面的场景:

JSF 页……

 <h:selectOneMenu value="#{country.localeCode}" onchange="submit()">
	<f:valueChangeListener type="com.mkyong.CountryValueListener" />
   	<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu> 

国家管理的豆……

 package com.mkyong;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="country")
@SessionScoped
public class CountryBean implements Serializable{

        private String localeCode;

	public void setLocaleCode(String localeCode) {
		this.localeCode = localeCode;
	}
	//...
} 

ValueChangeListener…

 package com.mkyong;

import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;

public class CountryValueListener implements ValueChangeListener{

	@Override
	public void processValueChange(ValueChangeEvent event)
			throws AbortProcessingException {

		//how to access the existing country managed bean?
		//country.setLocaleCode(event.getNewValue().toString());

	}

} 

解决办法

实际上,有许多方法可以从事件侦听器类或另一个受管 bean 访问现有的受管 bean。参见示例:

1.getApplicationMap()

如果在应用程序范围内声明了国家管理的 bean。

 CountryBean country = (CountryBean) FacesContext.getCurrentInstance().
		getExternalContext().getApplicationMap().get("country"); 

2.getRequestMap()

如果在请求范围内声明了国家管理的 bean。

 CountryBean country = (CountryBean) FacesContext.getCurrentInstance().
		getExternalContext().getRequestMap().get("country"); 

3.getSessionMap()

如果在会话范围内声明了国家管理的 bean。

 CountryBean country = (CountryBean) FacesContext.getCurrentInstance().
		getExternalContext().getSessionMap().get("country"); 

4.ELResolver()

使用 ELResolver。

 FacesContext context = FacesContext.getCurrentInstance();
	  CountryBean country = (CountryBean) context.
	    getELContext().getELResolver().getValue(context.getELContext(), null,"country"); 

5.ValueExpression()

使用 ValueExpression。

 FacesContext context = FacesContext.getCurrentInstance();
	  CountryBean country = (CountryBean) context.getApplication().getExpressionFactory()
            .createValueExpression(context.getELContext(), "#{country}", CountryBean.class)
              .getValue(context.getELContext()); 

6.evaluateExpressionGet()

使用 evaluateexprrecessionet。

 FacesContext context = FacesContext.getCurrentInstance();
	  CountryBean country = (CountryBean)context.getApplication()
            .evaluateExpressionGet(context, "#{country}", CountryBean.class); 

参考

  1. getApplicationMap()Java Doc
  2. getRequestMap() JavaDoc
  3. getSessionMap() JavaDoc
  4. getELResolver() JavaDoc
  5. createValueExpression()JavaDoc
  6. evaluateExpressionGet()JavaDoc

jsf2

Android 活动–从一个屏幕到另一个屏幕

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-activity-from-one-screen-to-another-screen/

在 Android 中,一个活动代表一个屏幕。大多数应用程序都有多个活动来表示不同的屏幕,例如,一个活动显示应用程序设置列表,另一个活动显示应用程序状态。

Note
Refer to this official Android activity article to understand more about Android activity.

在本教程中,我们将向您展示如何与活动交互,当单击一个按钮时,从当前屏幕(当前活动)导航到另一个屏幕(另一个活动)。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.XML 布局

在“res/layout/”文件夹中创建以下两个 XML 布局文件:

  1. res/layout/main.xml–代表屏幕 1
  2. res/layout/main2.xml–代表屏幕 2

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I&apos;m screen 1 (main.xml)"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Click me to another screen" />

</LinearLayout> 

文件:res/layout/main2.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I&apos;m screen 2 (main2.xml)"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout> 

2.活动

创建两个活动类别:

  1. AppActivity.java –> main . XML
  2. App2Activity.java –> main 2 . XML

要从一个屏幕导航到另一个屏幕,请使用以下代码:

 Intent intent = new Intent(context, anotherActivity.class);
    startActivity(intent); 

文件:AppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

public class AppActivity extends Activity {

	Button button;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		addListenerOnButton();
	}

	public void addListenerOnButton() {

		final Context context = this;

		button = (Button) findViewById(R.id.button1);

		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

			    Intent intent = new Intent(context, App2Activity.class);
                            startActivity(intent);   

			}

		});

	}

} 

文件:App2Activity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;

public class App2Activity extends Activity {

	Button button;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main2);
	}

} 

3.AndroidManifest.xml

AndroidManifest.xml中声明以上两个活动类。

文件:AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".AppActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:label="@string/app_name"
            android:name=".App2Activity" >
        </activity>
    </application>

</manifest> 

4.演示

运行应用程序。

显示AppActivity.java (main.xml)画面。

android activity demo1

当点击上述按钮时,它将导航到另一个屏幕App2Activity.java (main2.xml)。

android activity demo2

下载源代码

Download it – Android-From-Screen-To-Screen-Acticity-Example.zip (16 KB)

参考

  1. 安卓活动示例

Tags : android android activity

Android 警告对话框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-alert-dialog-example/

在本教程中,我们将向您展示如何在 Android 中显示一个警告框。参见流程步骤:

  1. 首先,使用AlertDialog.Builder创建警告框界面,如标题、要显示的消息、按钮和按钮 onclick 功能
  2. 稍后将上述生成器附加到AlertDialog并显示。
  3. 完成了。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1 个 Android 布局文件

简单布局文件,在屏幕上显示一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonAlert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Alert Box" />

</LinearLayout> 

2.活动

当用户点击此按钮时,显示警告框,带有您预先定义的警告对话框界面。

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	final Context context = this;
	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonAlert);

		// add button listener
		button.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View arg0) {

			AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
				context);

			// set title
			alertDialogBuilder.setTitle("Your Title");

			// set dialog message
			alertDialogBuilder
				.setMessage("Click yes to exit!")
				.setCancelable(false)
				.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog,int id) {
						// if this button is clicked, close
						// current activity
						MainActivity.this.finish();
					}
				  })
				.setNegativeButton("No",new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog,int id) {
						// if this button is clicked, just close
						// the dialog box and do nothing
						dialog.cancel();
					}
				});

				// create alert dialog
				AlertDialog alertDialog = alertDialogBuilder.create();

				// show it
				alertDialog.show();
			}
		});
	}
} 

3.演示

启动它,显示一个按钮。

android alert box example

单击按钮时,显示警告框

android alert box example

如果点击“是”按钮,关闭活动并返回到您的 Android 主屏幕。

android alert box example

下载源代码

Download it – Android-Alert-Dialogl-Example.zip (16 KB)

参考

  1. Android alert dialog Javadoc
  2. 安卓对话框示例

Android 模拟时钟和数字时钟示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-analogclock-and-digitalclock-example/

在安卓系统中, AnalogClock 是一个双手时钟,一个用于小时指示器,另一个用于分钟指示器。数字时钟看起来就像你手上的普通数字手表,以数字格式显示小时、分钟和秒。

AnalogClockDigitalClock都不能修改时间,如果要修改时间,请使用“时间选择器”。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.模拟时钟和数字时钟

打开“ res/layout/main.xml 文件,在 xml 中添加AnalogClockDigitalClock

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Analog Clock"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <AnalogClock
        android:id="@+id/analogClock1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Digital Clock"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <DigitalClock
        android:id="@+id/digitalClock1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DigitalClock" />

</LinearLayout> 

2.代码代码

不知道我能用AnalogClockDigitalClock做什么。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.AnalogClock;
import android.widget.DigitalClock;

public class MyAndroidAppActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		AnalogClock ac = (AnalogClock) findViewById(R.id.analogClock1);
		//what can i do with AnalogClock?

		DigitalClock dc = (DigitalClock) findViewById(R.id.digitalClock1);
		//what can i do with DigitalClock also? for display only

	}

} 

3.演示

运行应用程序。

1.这是模拟时钟和数字时钟的样子:

android analogclock and digitalclock demo

下载源代码

Download it – Android-AnalogClock-DigitalClock-Example.zip (15 KB)

参考

  1. Android digital clock JavaDoc
  2. Android analog clock JavaDoc

android clock

Android 按钮示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-button-example/

在 Android 中,只需使用“ android.widget.Button ”类显示一个普通按钮即可。

在本教程中,我们向你展示如何显示一个普通的按钮,添加一个点击监听器,当用户点击按钮时,在你的 Android 的互联网浏览器中打开一个 URL。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

Note
For more advance function, like image, please refer to this ImageButton example and also this ImageButton selector example.

1.添加按钮

打开" res/layout/main.xml 文件,添加一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button - Go to mkyong.com" />

</LinearLayout> 

2.代码代码

给按钮附加一个点击监听器。

当用户点击它时,打开手机浏览器并显示网址:http://www.mkyong.com

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

public class MyAndroidAppActivity extends Activity {

	Button button;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		addListenerOnButton();

	}

	public void addListenerOnButton() {

		button = (Button) findViewById(R.id.button1);

		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

			  Intent browserIntent = 
                            new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.mkyong.com"));
			    startActivity(browserIntent);

			}

		});

	}

} 

3.演示

运行应用程序。

1.结果,一个正常的按钮。

android button demo1

2.点击按钮,在浏览器中显示网址。

android button demo2

下载源代码

Download it – Android-Button-Example.zip (15 KB)

参考

  1. 安卓按钮 JavaDoc

android button

Android 复选框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-checkbox-example/

在 Android 中,可以使用“ android.widget.CheckBox ”类来渲染一个复选框。

在本教程中,我们将向您展示如何在 XML 文件中创建 3 个复选框,并演示如何使用监听器来检查复选框的状态-选中或未选中。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.自定义字符串

打开" res/values/strings.xml 文件,添加一些用户自定义的字符串。

文件:res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, MyAndroidAppActivity!
    <string name="app_name">MyAndroidApp
    <string name="chk_ios">IPhone
    <string name="chk_android">Android
    <string name="chk_windows">Windows Mobile
    <string name="btn_display">Display
</resources> 

2.检验盒

打开“ res/layout/main.xml 文件,在LinearLayout里面添加 3 个“复选框和一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <CheckBox
        android:id="@+id/chkIos"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/chk_ios" />

    <CheckBox
        android:id="@+id/chkAndroid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/chk_android"
        android:checked="true" />

    <CheckBox
        android:id="@+id/chkWindows"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/chk_windows" />

    <Button
        android:id="@+id/btnDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_display" />

</LinearLayout> 

Make CheckBox is checked by default
Put android:checked="true" inside checkbox element to make it checked bu default. In this case, “Android” option is checked by default. ## 3.代码代码

在 activity " onCreate()"方法中附加侦听器,以监视以下事件:

  1. 如果复选框 id : " chkIos "被选中,则显示一个浮动框,显示消息"兄弟,试试 Android "。
  2. 如果按钮被单击,则显示一个浮动框并显示复选框状态。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

  private CheckBox chkIos, chkAndroid, chkWindows;
  private Button btnDisplay;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addListenerOnChkIos();
	addListenerOnButton();
  }

  public void addListenerOnChkIos() {

	chkIos = (CheckBox) findViewById(R.id.chkIos);

	chkIos.setOnClickListener(new OnClickListener() {

	  @Override
	  public void onClick(View v) {
                //is chkIos checked?
		if (((CheckBox) v).isChecked()) {
			Toast.makeText(MyAndroidAppActivity.this,
		 	   "Bro, try Android :)", Toast.LENGTH_LONG).show();
		}

	  }
	});

  }

  public void addListenerOnButton() {

	chkIos = (CheckBox) findViewById(R.id.chkIos);
	chkAndroid = (CheckBox) findViewById(R.id.chkAndroid);
	chkWindows = (CheckBox) findViewById(R.id.chkWindows);
	btnDisplay = (Button) findViewById(R.id.btnDisplay);

	btnDisplay.setOnClickListener(new OnClickListener() {

          //Run when button is clicked
	  @Override
	  public void onClick(View v) {

		StringBuffer result = new StringBuffer();
		result.append("IPhone check : ").append(chkIos.isChecked());
		result.append("\nAndroid check : ").append(chkAndroid.isChecked());
		result.append("\nWindows Mobile check :").append(chkWindows.isChecked());

		Toast.makeText(MyAndroidAppActivity.this, result.toString(),
				Toast.LENGTH_LONG).show();

	  }
	});

  }
} 

4.演示

运行应用程序。

1.结果:

android checkbox demo 1

2.如果选中了“IPhone ”:

android checkbox demo2

3.勾选了“IPhone”和“Windows Mobile”,之后,点击“显示”按钮:

android checkbox demo3

下载源代码

Download it – Android-Checkbox-Example.zip (15 KB)

参考

  1. Android 复选框 JavaDoc
  2. Android 复选框示例

android checkbox

Android 自定义对话框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-custom-dialog-example/

在本教程中,我们将向您展示如何在 Android 中创建自定义对话框。请参见以下步骤:

  1. 创建自定义对话框布局(XML 文件)。
  2. 将布局附在Dialog上。
  3. 显示Dialog
  4. 完成了。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

Note
You may also interest to read this custom AlertDialog example.

1 个 Android 布局文件

两个 XML 文件,一个用于主屏幕,一个用于自定义对话框。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonShowCustomDialog"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Custom Dialog" />

</LinearLayout> 

文件:res/layout/custom.xml

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp" />

    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#FFF" 
        android:layout_toRightOf="@+id/image"/>/>

     <Button
        android:id="@+id/dialogButtonOK"
        android:layout_width="100px"
        android:layout_height="wrap_content"
        android:text=" Ok "
        android:layout_marginTop="5dp"
        android:layout_marginRight="5dp"
        android:layout_below="@+id/image"
        />

</RelativeLayout> 

2.活动

阅读下一步的评论和演示,这应该是自我探索。

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity {

	final Context context = this;
	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonShowCustomDialog);

		// add button listener
		button.setOnClickListener(new OnClickListener() {

		  @Override
		  public void onClick(View arg0) {

			// custom dialog
			final Dialog dialog = new Dialog(context);
			dialog.setContentView(R.layout.custom);
			dialog.setTitle("Title...");

			// set the custom dialog components - text, image and button
			TextView text = (TextView) dialog.findViewById(R.id.text);
			text.setText("Android custom dialog example!");
			ImageView image = (ImageView) dialog.findViewById(R.id.image);
			image.setImageResource(R.drawable.ic_launcher);

			Button dialogButton = (Button) dialog.findViewById(R.id.dialogButtonOK);
			// if button is clicked, close the custom dialog
			dialogButton.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					dialog.dismiss();
				}
			});

			dialog.show();
		  }
		});
	}
} 

3.演示

启动它,显示“main.xml”布局。

android custom dialog example

点击按钮,显示自定义对话框"custom.xml"布局,如果点击"确定"按钮,对话框将被关闭。

android custom dialog example

下载源代码

Download it – Android-Custom-Dialog-Example.zip (16 KB)

参考

  1. 安卓对话框 Javadoc
  2. 安卓对话框示例
  3. 安卓相对布局示例
  4. Android 提示对话框(自定义 AlertDialog)示例

Android 日期选择器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-date-picker-example/

在 Android 中,您可以使用“Android . widget . date picker”类来呈现一个日期选择器组件,以便在预定义的用户界面中选择日、月和年。

在本教程中,我们将向您展示如何通过Android . widget . date picker在当前页面中呈现日期选择器组件,以及通过Android . app . datepickerdialog在对话框中呈现日期选择器组件。此外,我们还向您展示了如何在日期选择器组件中设置日期。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.日期选择器

打开“ res/layout/main.xml ”文件,添加日期选择器、标签和按钮进行演示。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnChangeDate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change Date" />

    <TextView
        android:id="@+id/lblDate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Current Date (M-D-YYYY): "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/tvDate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <DatePicker
        android:id="@+id/dpResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout> 

"DatePickerDialog"是在代码中声明,而不是在 XML 中。

2.代码代码

阅读代码的注释,应该是不言自明的。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import java.util.Calendar;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;

public class MyAndroidAppActivity extends Activity {

	private TextView tvDisplayDate;
	private DatePicker dpResult;
	private Button btnChangeDate;

	private int year;
	private int month;
	private int day;

	static final int DATE_DIALOG_ID = 999;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		setCurrentDateOnView();
		addListenerOnButton();

	}

	// display current date
	public void setCurrentDateOnView() {

		tvDisplayDate = (TextView) findViewById(R.id.tvDate);
		dpResult = (DatePicker) findViewById(R.id.dpResult);

		final Calendar c = Calendar.getInstance();
		year = c.get(Calendar.YEAR);
		month = c.get(Calendar.MONTH);
		day = c.get(Calendar.DAY_OF_MONTH);

		// set current date into textview
		tvDisplayDate.setText(new StringBuilder()
			// Month is 0 based, just add 1
			.append(month + 1).append("-").append(day).append("-")
			.append(year).append(" "));

		// set current date into datepicker
		dpResult.init(year, month, day, null);

	}

	public void addListenerOnButton() {

		btnChangeDate = (Button) findViewById(R.id.btnChangeDate);

		btnChangeDate.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				showDialog(DATE_DIALOG_ID);

			}

		});

	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DATE_DIALOG_ID:
		   // set date picker as current date
		   return new DatePickerDialog(this, datePickerListener, 
                         year, month,day);
		}
		return null;
	}

	private DatePickerDialog.OnDateSetListener datePickerListener 
                = new DatePickerDialog.OnDateSetListener() {

		// when dialog box is closed, below method will be called.
		public void onDateSet(DatePicker view, int selectedYear,
				int selectedMonth, int selectedDay) {
			year = selectedYear;
			month = selectedMonth;
			day = selectedDay;

			// set selected date into textview
			tvDisplayDate.setText(new StringBuilder().append(month + 1)
			   .append("-").append(day).append("-").append(year)
			   .append(" "));

			// set selected date into datepicker also
			dpResult.init(year, month, day, null);

		}
	};

} 

上面的“DatePickerDialog”例子是从谷歌 Android 日期选择器例子 引用的,有一些小的变化。

3.演示

运行应用程序。

1.结果,“日期选择器”和“文本视图”被设置为当前日期。

android datepicker demo1

2.点击“更改日期”按钮,将通过DatePickerDialog在对话框中提示一个日期选择器组件。

android datepicker demo2

3.“日期选择器”和“文本视图”都用选定的日期更新。

android datepicker demo3

下载源代码

Download it – Android-DatePicker-Example.zip (16 KB)

参考

  1. Android 日期选择器示例
  2. Android DatePicker JavaDoc
  3. Android datepicker 对话框 javadoc】t1

Tags : android date date picker

Android 在真实设备上的调试

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-debugging-on-real-device/

本教程将向你展示如何在一个真正的 Android 设备(手机)上调试 Android 应用程序。

本教程中的工具和环境:

  1. Eclipse IDE 3.7 + ADT 插件
  2. 三星银河 S2
  3. Windows 7

在设备上调试的总结步骤:

  1. 下载 Google USB 驱动程序(如果使用 Android 开发者手机(ADP))
  2. 下载 OEM USB 驱动程序(如果使用其他 Android 驱动的设备,三星、宏基、HTC…)
  3. 在您的设备中,打开 USB 调试。
  4. 将您的设备连接到 PC。
  5. 使用“adb 设备”验证您的设备是否连接成功。
  6. 将 Eclipse 的“部署目标选择模式”改为“手动”,在运行时选择设备。
  7. 完成了。

在这个例子中,我们将使用前面的“ Hello World Android 示例”,并在一个真正的 Android 驱动的设备上调试或运行,三星 Galaxy S2

1.下载 OEM USB 驱动程序

参考这个安卓 USB 驱动指南。如果你正在使用像 Nexus One 或 Nexus S 这样的 Android 开发者手机(ADP),你应该通过“ Android SDK 管理器安装谷歌 USB 驱动程序。

使用三星 Galaxy S2,您需要安装 OEM USB 驱动程序,或三星 USB 驱动程序,它包含在三星 Kies 软件中。

请参阅此“何处下载三星 Galaxy S2 USB 驱动程序”指南,在您的电脑上安装 USB 驱动程序。

get samsung USB driver ## 2.启用 USB 调试

在您的设备中,要打开 USB 调试:“设置”->“应用程序”->“开发”->“USB 调试”。

见下图:

enable usb debugging on Android ## 3.将设备连接到 PC

将三星 Galaxy S2 连接到 PC,并通过命令“adb devices”进行验证。

在命令提示符下,将路径更改为“Android SDK/platform-tools,输入命令“adb devices”,如果看到类似“某个号码奇怪的设备”的东西,说明你的设备已经成功连接到 PC。

图——“304d 19665059 df6e 设备”是三星 Galaxy S2。

adb devices

4.Eclipse -> Android

Note
Most people are stuck in this stage, beware.

之前,您可能创建了几个“ Android 虚拟设备(AVD) 用于测试,并将“部署目标选择模式”设置为“自动”,但是,这将导致应用程序无法在您连接的设备上调试,并继续启动 AVD 仿真器。

2 个解决方案:

  1. 在 Eclipse 中右击 Android 项目,选择"运行 " - > " 运行配置 " - > " Android 应用 " - > " 目标 " tab - > " 部署目标选择模式 " - >设置为"手动",就可以在运行时选择设备了。
  2. 或者,在部署目标选择模式中,取消选择所有选中的 AVD 即可。

图:部署目标选择模式

android eclipse deployment target

图:运行时选择您的设备

select device at runtime

5.启动它

在 Eclipse 中,将您的项目作为 Android 项目运行或调试,在运行时选择您的设备,项目将复制到您的三星 Galaxy S2 并自动启动。

图:HelloWorldApp 在三星 galaxy S2 上调试。

android hello worldandroid hello world

参考

  1. 在真实设备上开发 Android】
  2. 安卓 OEM USB 驱动
  3. Android 在三星 Galaxy S2 上的调试
  4. 安卓 hello world 示例

android debug

Android GridView 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-gridview-example/

在 Android 中,GridView让你在二维滚动网格中排列组件。有关详细的属性解释,请参见 GridView 参考。

在本教程中,我们将向您展示两个常见的GridView示例:

  1. 正常方式,只是在GridView布局中显示文本。
  2. 创建自定义适配器以在GridView布局中显示图像和文本。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.普通 GridView 示例

GridView布局中显示从 A 到 Z 的字符。很简单,应该是不言自明的。

1.1 Android 布局文件–RES/Layout/main . XML

 <?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridView1"
    android:numColumns="auto_fit"
    android:gravity="center"
    android:columnWidth="50dp"
    android:stretchMode="columnWidth"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

</GridView> 

1.2 活动

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;

public class GridViewActivity extends Activity {

	GridView gridView;

	static final String[] numbers = new String[] { 
			"A", "B", "C", "D", "E",
			"F", "G", "H", "I", "J",
			"K", "L", "M", "N", "O",
			"P", "Q", "R", "S", "T",
			"U", "V", "W", "X", "Y", "Z"};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		gridView = (GridView) findViewById(R.id.gridView1);

		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_1, numbers);

		gridView.setAdapter(adapter);

		gridView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View v,
				int position, long id) {
			   Toast.makeText(getApplicationContext(),
				((TextView) v).getText(), Toast.LENGTH_SHORT).show();
			}
		});

	}

} 

1.3 演示

android grid view example

2.自定义适配器示例

在这个例子中,扩展一个BaseAdapter以在GridView布局中显示一组图像和文本。

2.1 两个 Android 布局文件

File–RES/layout/main . XML

 <?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridView1"
    android:numColumns="auto_fit"
    android:gravity="center"
    android:columnWidth="100dp"
    android:stretchMode="columnWidth"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

</GridView> 

File–RES/layout/mobile . XML

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/grid_item_image"
        android:layout_width="50px"
        android:layout_height="50px"
        android:layout_marginRight="10px"
        android:src="@drawable/android_logo" >
    </ImageView>

    <TextView
        android:id="@+id/grid_item_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@+id/label"
        android:layout_marginTop="5px"
        android:textSize="15px" >
    </TextView>

</LinearLayout> 

2.2 定制适配器

 package com.mkyong.android.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.mkyong.android.R;

public class ImageAdapter extends BaseAdapter {
	private Context context;
	private final String[] mobileValues;

	public ImageAdapter(Context context, String[] mobileValues) {
		this.context = context;
		this.mobileValues = mobileValues;
	}

	public View getView(int position, View convertView, ViewGroup parent) {

		LayoutInflater inflater = (LayoutInflater) context
			.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		View gridView;

		if (convertView == null) {

			gridView = new View(context);

			// get layout from mobile.xml
			gridView = inflater.inflate(R.layout.mobile, null);

			// set value into textview
			TextView textView = (TextView) gridView
					.findViewById(R.id.grid_item_label);
			textView.setText(mobileValues[position]);

			// set image based on selected text
			ImageView imageView = (ImageView) gridView
					.findViewById(R.id.grid_item_image);

			String mobile = mobileValues[position];

			if (mobile.equals("Windows")) {
				imageView.setImageResource(R.drawable.windows_logo);
			} else if (mobile.equals("iOS")) {
				imageView.setImageResource(R.drawable.ios_logo);
			} else if (mobile.equals("Blackberry")) {
				imageView.setImageResource(R.drawable.blackberry_logo);
			} else {
				imageView.setImageResource(R.drawable.android_logo);
			}

		} else {
			gridView = (View) convertView;
		}

		return gridView;
	}

	@Override
	public int getCount() {
		return mobileValues.length;
	}

	@Override
	public Object getItem(int position) {
		return null;
	}

	@Override
	public long getItemId(int position) {
		return 0;
	}

} 

2.3 活动

 package com.mkyong.android;

import com.mkyong.android.adapter.ImageAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;

public class GridViewActivity extends Activity {

	GridView gridView;

	static final String[] MOBILE_OS = new String[] { 
		"Android", "iOS","Windows", "Blackberry" };

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		gridView = (GridView) findViewById(R.id.gridView1);

		gridView.setAdapter(new ImageAdapter(this, MOBILE_OS));

		gridView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {
				Toast.makeText(
				   getApplicationContext(),
				   ((TextView) v.findViewById(R.id.grid_item_label))
				   .getText(), Toast.LENGTH_SHORT).show();

			}
		});

	}

} 

2.4 演示

android gridview custom adapter example

下载源代码

Download it – Android-GridView-Example.zip (21 KB)

参考

  1. GridView Javadoc
  2. Android GridView 示例
  3. Android ListView 示例

Android hello world 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-hello-world-example/

在本教程中,我们将向您展示如何在 Eclipse IDE + ADT 插件中创建一个简单的“hello world”Android项目,并使用 Android 虚拟设备(AVD) 运行它。Eclipse ADT 插件提供了简单的 Android 项目创建和管理、组件拖放、自动完成和许多有用的特性来加速您的 Android 开发周期。

开发 Android 应用程序的步骤概述:

  1. 安装 Android SDK
  2. 安装 ADT Eclipse 插件
  3. 创建一个 Android 虚拟设备(AVD)
  4. 用 Eclipse 创建 Android 项目(向导)
  5. 编码它…
  6. 在 Android 虚拟设备(AVD)中启动

本教程中使用的工具:

  1. JDK 1.6
  2. Eclipse IDE 3.7,Indigo
  3. Android SDK

1.安装 Android SDK

访问这个 Android SDK 页面,选择哪个平台并安装。

在 Android SDK 安装文件夹中,运行“Android SDK 管理器”,选择你要开发的 Android 版本。

android sdk manager

2.安装 ADT Eclipse 插件

要将 Android SDK 与 Eclipse IDE 集成,需要安装 Eclipse ADT 插件。请参考本官方指南-“安装 ADT 插件”。

在 Eclipse IDE 中,选择“帮助”->“安装新软件……”,并输入以下 URL:

 https://dl-ssl.google.com/android/eclipse/ 

android ADT pluginNote
In my case, above ADT plugin is taking years to download, no idea why. If you are facing the similar problem, just download and install the ADT plugin manually, refer to this ADT plugin troubleshooting guide.

3.创建一个 Android 虚拟设备(AVD)

在 Eclipse 中,可以访问 Eclipse 工具栏中的“ Android 虚拟设备(AVD) ”。单击“新建”创建一个 AVD。

android avd manager

稍后,Eclipse 会将应用程序部署到这个 AVD 中。

4.创建 Android 项目

在 Eclipse 中,选择“文件->新建->项目…”,“Android 项目”,并输入您的应用程序详细信息。Eclipse 将创建所有必要的 Android 项目文件和配置。

Eclipse new android project wizardfolder structure

5.你好世界

定位生成的活动文件,修改一点输出一个字符串“Hello World”。

文件:HelloWorldActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloWorldActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView text = new TextView(this);
        text.setText("Hello World, Android - mkyong.com");
        setContentView(text);
    }
} 

6.演示

作为“ Android 应用运行,见输出。

hello world output

按下“主页”按钮(在右手边),你会注意到“HelloWorld”应用程序已成功部署在 Android 虚拟设备上。

android deployedNote
This tutorial is more to example driven, not much explanation. For detail and complete explanation, please refer to the official Android developer hello world tutorial.Firewall…
In my computer, the COMODO firewall is installed and blocked the deploying process, caused the connection between Eclipse ADT and AVD is blocked and failed to deploy. Just make sure your firewall is configured properly, or just turn it off for Android development 🙂Debug Android application on real device
Sometime, “Android Virtual Device” is not enough to test some real phone functionalities, like led light, sensor and etc. Then you should refer to this how to debug Android application on real device.

下载源代码

Download it – Android-HelloWorld.zip (15 KB)

参考

  1. 安卓开发者

Tags : android hello world

Android——如何将按钮置于屏幕中央

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-how-to-center-button-on-screen/

一个小的 Android 提示,告诉你如何在屏幕上居中按钮。将按钮包裹在RelativeLayout中,并将以下属性设置为“”。

 android:layout_centerVertical="true"
android:layout_centerHorizontal="true" 

下面是一个完整的例子,演示了如何使用上面的提示在屏幕上居中一个按钮。

1.Android 布局

布局中的按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:layout_centerVertical="true"
       	android:layout_centerHorizontal="true"
        android:text="Button" />

</RelativeLayout> 

2.活动

简单的活动类,什么也不做,只显示上面的布局文件。

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;

public class HelloWorldActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
} 

3.演示

启动它,并查看输出:

center button on screen

下载源代码

Download it – Android-Center-Button-On-Screen-Example.zip (16 KB)

参考

  1. Android relative layout layout params Javadoc

android button center

Android:如何检查设备是否有摄像头

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-how-to-check-if-device-has-camera/

在 Android 中,您可以使用PackageManagerhasSystemFeature()方法来检查设备是否具有摄像头、gps 或其他功能。

查看在活动类中使用PackageManager的完整示例。

 package com.mkyong.android;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

public class FlashLightActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//setContentView(R.layout.main);

		Context context = this;
		PackageManager packageManager = context.getPackageManager();

		// if device support camera?
		if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
			//yes
			Log.i("camera", "This device has camera!");
		}else{
			//no
			Log.i("camera", "This device has no camera!");
		}

	}
} 

Camera flashlight example
You may interest on this example – How to turn on/off camera LED/flashlight in Android.

参考

  1. Android package manager Javadoc

android camera (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214233023/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Android ImageButton 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-imagebutton-example/

在 Android 中,您可以使用“Android . widget . imagebutton”来显示一个普通的“Button”,并带有自定义的背景图像。

在本教程中,我们将向您展示如何显示一个带有背景图片的按钮,名为“ android_button.png ”,当用户点击它时,会显示一条短消息。就这么简单。

Note
You may also like this Android ImageButton selector example, which allow to change button’s images depends on button states.

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.将图像添加到资源

将 image "Android _ button . png"放入" res/drawable-?dpi 文件夹。以便 Android 知道在哪里可以找到您图像。

2.添加 ImageButton

打开“ res/layout/main.xml 文件,添加一个“ImageButton标签,通过“android:src定义背景图片。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageButton
        android:id="@+id/imageButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/android_button" />

</LinearLayout> 

3.代码代码

下面是代码,在图像按钮上添加一个点击监听器。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageButton;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;

public class MyAndroidAppActivity extends Activity {

	ImageButton imageButton;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		addListenerOnButton();

	}

	public void addListenerOnButton() {

		imageButton = (ImageButton) findViewById(R.id.imageButton1);

		imageButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

			   Toast.makeText(MyAndroidAppActivity.this,
				"ImageButton is clicked!", Toast.LENGTH_SHORT).show();

			}

		});

	}

} 

4.演示

运行应用程序。

1.结果,带有自定义背景图像的按钮。

android imagebutton demo1

2.点击按钮,显示一条短消息。

android imagebutton demo2

下载源代码

Download it – Android-ImageButton-Example.zip (28 KB)

参考

  1. Android ImageButton 示例

android imagebutton

Android 线性布局示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-linearlayout-example/

在 Android 中, LinearLayout 是一种常见的布局,通过orientation属性将“组件”按垂直或水平顺序排列。此外,最高的weight组件将填充LinearLayout中的剩余空间。

在本教程中,我们将向你展示如何使用LinearLayout以垂直和水平顺序显示 3 个按钮,以及“权重”是如何工作的。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.线性布局–水平

打开“ res/layout/main.xml ”文件,在LinearLayout内添加 3 个按钮,方向为“水平”。在这种情况下,权重最高的是“button3”,因此它将填满布局中的剩余空间。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 2" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 3" 
        android:layout_weight="1"/>

</LinearLayout> 

见图:

android linearlayout demo1 ## 2.线性布局–垂直

现在,将LinearLayout改为垂直方向。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 2" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 3" 
        android:layout_weight="1"/>

</LinearLayout> 

见图:

android linearlayout demo2 ## 下载源代码

Download it – Android-LinearLayout-Example.zip (15 KB)

参考

  1. Android LinearLayout 示例
  2. Android linear layout JavaDoc

android layout linearlayout

Android ListView 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-listview-example/

在 Android 中, ListView 允许你在一个垂直的可滚动列表中排列组件。

在本教程中,我们将向您展示 2 个ListView示例:

  1. ListView中显示组件的正常方式。
  2. 自定义数组适配器,用于自定义ListView中的项目显示。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.普通 ListView 示例

在这个例子中,我们向你展示了如何通过ListView来显示水果名称的列表,这应该是简单明了的。

1.1 Android 布局文件

文件:res/layout/list_fruit.xml

 <?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="20sp" >
</TextView> 

1.2 ListView

 package com.mkyong.android;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class ListFruitActivity extends ListActivity {

	static final String[] FRUITS = new String[] { "Apple", "Avocado", "Banana",
			"Blueberry", "Coconut", "Durian", "Guava", "Kiwifruit",
			"Jackfruit", "Mango", "Olive", "Pear", "Sugar-apple" };

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// no more this
		// setContentView(R.layout.list_fruit);

		setListAdapter(new ArrayAdapter<String>(this, R.layout.list_fruit,FRUITS));

		ListView listView = getListView();
		listView.setTextFilterEnabled(true);

		listView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
			    // When clicked, show a toast with the TextView text
			    Toast.makeText(getApplicationContext(),
				((TextView) view).getText(), Toast.LENGTH_SHORT).show();
			}
		});

	}

} 

1.3 演示

android listview example ## 2.自定义数组适配器示例

在这个例子中,我们展示了如何在ListView中创建 4 个项目,并使用一个自定义的ArrayAdapter来根据列表中的“项目名称”显示不同的图像。

2.1 图像
获取 4 幅图像进行演示。

images in android project

2.2 Android 布局文件
文件:res/layout/list_mobile.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/logo"
        android:layout_width="50px"
        android:layout_height="50px"
        android:layout_marginLeft="5px"
        android:layout_marginRight="20px"
        android:layout_marginTop="5px"
        android:src="@drawable/windowsmobile_logo" >
    </ImageView>

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@+id/label"
        android:textSize="30px" >
    </TextView>

</LinearLayout> 

2.3 自定义 ArrayAdapter
创建一个类扩展ArrayAdapter并在getView()方法中自定义项目显示。

 package com.mkyong.android.adaptor;

import com.mkyong.android.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MobileArrayAdapter extends ArrayAdapter<String> {
	private final Context context;
	private final String[] values;

	public MobileArrayAdapter(Context context, String[] values) {
		super(context, R.layout.list_mobile, values);
		this.context = context;
		this.values = values;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		LayoutInflater inflater = (LayoutInflater) context
			.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		View rowView = inflater.inflate(R.layout.list_mobile, parent, false);
		TextView textView = (TextView) rowView.findViewById(R.id.label);
		ImageView imageView = (ImageView) rowView.findViewById(R.id.logo);
		textView.setText(values[position]);

		// Change icon based on name
		String s = values[position];

		System.out.println(s);

		if (s.equals("WindowsMobile")) {
			imageView.setImageResource(R.drawable.windowsmobile_logo);
		} else if (s.equals("iOS")) {
			imageView.setImageResource(R.drawable.ios_logo);
		} else if (s.equals("Blackberry")) {
			imageView.setImageResource(R.drawable.blackberry_logo);
		} else {
			imageView.setImageResource(R.drawable.android_logo);
		}

		return rowView;
	}
} 

2.4 ListView
ListView,但是使用上面的自定义适配器来显示列表。

 package com.mkyong.android;

import com.mkyong.android.adaptor.MobileArrayAdapter;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.Toast;
import android.view.View;

public class ListMobileActivity extends ListActivity {

	static final String[] MOBILE_OS = 
               new String[] { "Android", "iOS", "WindowsMobile", "Blackberry"};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setListAdapter(new MobileArrayAdapter(this, MOBILE_OS));

	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {

		//get selected items
		String selectedValue = (String) getListAdapter().getItem(position);
		Toast.makeText(this, selectedValue, Toast.LENGTH_SHORT).show();

	}

} 

2.5 演示

android custom array adapter example ## 下载源代码

Download both examples – Android-ListView-Example.zip (21 KB)

参考

  1. Android ListView 示例
  2. Android ListView JavaDoc

android listview

Android 密码字段示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-password-field-example/

在 Android 中,可以使用“ android.widget.EditText ”,配合inputType="textPassword"渲染一个密码组件。

在本教程中,我们将向您展示如何使用 XML 来创建密码字段、标签字段和普通按钮。当您点击按钮时,密码值将显示为浮动消息(toast 消息)。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.自定义字符串

打开" res/values/strings.xml 文件,添加一些自定义字符串进行演示。

文件:res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MyAndroidApp
    <string name="lblPassword">Enter Your Password :
    <string name="btn_submit">Submit
</resources> 

2.密码

打开“ res/layout/main.xml 文件,添加密码组件,EditText + inputType="textPassword"

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/lblPassword"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/lblPassword"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/txtPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPassword" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/btnSubmit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_submit" />

</LinearLayout> 

3.代码代码

在 activity " onCreate()"方法中,附加一个 click listener on 按钮,以显示密码值。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

  private EditText password;
  private Button btnSubmit;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addListenerOnButton();

  }

  public void addListenerOnButton() {

	password = (EditText) findViewById(R.id.txtPassword);	
	btnSubmit = (Button) findViewById(R.id.btnSubmit);

	btnSubmit.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {

		  Toast.makeText(MyAndroidAppActivity.this, password.getText(),
			Toast.LENGTH_SHORT).show();

		}

	});

  }
} 

4.演示

运行应用程序。

1.结果,显示密码字段。

android password demo1

2.键入密码“mkyong123 ”,然后单击提交按钮。

android password demo2

下载源代码

Download it – Android-Password-Example.zip (15 KB)

参考

  1. Android EditText JavaDoc

Android 进度条示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-progress-bar-example/

在 Android 中,进度条可以告诉用户任务需要更长的时间来完成。

在本教程中,我们将向您展示如何显示一个进度条对话框来告诉用户您的任务正在运行,以及如何增加进度条状态直到任务完成。

Note
Refer to this Android ProgressBar JavaDoc for detail explanation.

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.添加按钮

打开“ res/layout/main.xml 文件,只需添加普通按钮进行演示即可。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnStartProgress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Download File" />

</LinearLayout> 

2.代码代码

使用进度条的关键是使用“Thread”来运行您的耗时任务,并使用另一个“Thread”来相应地更新进度条状态。阅读代码的注释,应该是不言自明的。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

public class MyAndroidAppActivity extends Activity {

	Button btnStartProgress;
	ProgressDialog progressBar;
	private int progressBarStatus = 0;
	private Handler progressBarHandler = new Handler();

	private long fileSize = 0;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		addListenerOnButton();

	}

	public void addListenerOnButton() {

		btnStartProgress = (Button) findViewById(R.id.btnStartProgress);
		btnStartProgress.setOnClickListener(
                 new OnClickListener() {

		   @Override
		   public void onClick(View v) {

			// prepare for a progress bar dialog
			progressBar = new ProgressDialog(v.getContext());
			progressBar.setCancelable(true);
			progressBar.setMessage("File downloading ...");
			progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			progressBar.setProgress(0);
			progressBar.setMax(100);
			progressBar.show();

			//reset progress bar status
			progressBarStatus = 0;

			//reset filesize
			fileSize = 0;

			new Thread(new Runnable() {
			  public void run() {
				while (progressBarStatus < 100) {

				  // process some tasks
				  progressBarStatus = doSomeTasks();

				  // your computer is too fast, sleep 1 second
				  try {
					Thread.sleep(1000);
				  } catch (InterruptedException e) {
					e.printStackTrace();
				  }

				  // Update the progress bar
				  progressBarHandler.post(new Runnable() {
					public void run() {
					  progressBar.setProgress(progressBarStatus);
					}
				  });
				}

				// ok, file is downloaded,
				if (progressBarStatus >= 100) {

					// sleep 2 seconds, so that you can see the 100%
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					// close the progress bar dialog
					progressBar.dismiss();
				}
			  }
		       }).start();

	           }

                });

        }

	// file download simulator... a really simple
	public int doSomeTasks() {

		while (fileSize <= 1000000) {

			fileSize++;

			if (fileSize == 100000) {
				return 10;
			} else if (fileSize == 200000) {
				return 20;
			} else if (fileSize == 300000) {
				return 30;
			}
			// ...add your own

		}

		return 100;

	}

} 

“doSomeTasks”方法只是一个文件大小下载模拟器,只是用你的长时间运行的任务替换这个方法。

3.演示

运行应用程序。

1.结果,一个按钮。

android progress bar demo1

2.点击按钮,会提示一个“进度条对话框”显示当前下载进度。

android progress bar demo2

3.任务完成后,进度条会显示 100%,并自动关闭。

android progress bar demo3

下载源代码

Download it - Android-ProgressBar-Example.zip (15 KB)

参考

  1. 安卓进度条示例
  2. Android progress dialog JavaDoc
  3. 另一个 Android ProgressBar 例子

android progress bar

Android 提示用户输入对话框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-prompt-user-input-dialog-example/

在本教程中,我们将增强前面的 AlertDialog 示例,使其能够接受用户输入,就像一个提示对话框。更具体地说,这是一个自定义的AlertDialog示例。

请参见以下步骤:

  1. 创建提示对话框布局(XML 文件)。
  2. 将提示对话框布局附加到AlertDialog.Builder
  3. AlertDialog.Builder连接到AlertDialog上。
  4. 完成了。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

Note
You may interest to read this custom dialog example.

1 个 Android 布局文件

两个 XML 文件,一个用于主屏幕,一个用于提示对话框。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonPrompt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Prompt Dialog" />

    <EditText
        android:id="@+id/editTextResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

    </EditText>

</LinearLayout> 

文件:res/layout/prompts.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_root"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Type Your Message : "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editTextDialogUserInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <requestFocus />

    </EditText>

</LinearLayout> 

2.活动

阅读下一步的评论和演示,这应该是自我探索。

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

	final Context context = this;
	private Button button;
	private EditText result;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// components from main.xml
		button = (Button) findViewById(R.id.buttonPrompt);
		result = (EditText) findViewById(R.id.editTextResult);

		// add button listener
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				// get prompts.xml view
				LayoutInflater li = LayoutInflater.from(context);
				View promptsView = li.inflate(R.layout.prompts, null);

				AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
						context);

				// set prompts.xml to alertdialog builder
				alertDialogBuilder.setView(promptsView);

				final EditText userInput = (EditText) promptsView
						.findViewById(R.id.editTextDialogUserInput);

				// set dialog message
				alertDialogBuilder
					.setCancelable(false)
					.setPositiveButton("OK",
					  new DialogInterface.OnClickListener() {
					    public void onClick(DialogInterface dialog,int id) {
						// get user input and set it to result
						// edit text
						result.setText(userInput.getText());
					    }
					  })
					.setNegativeButton("Cancel",
					  new DialogInterface.OnClickListener() {
					    public void onClick(DialogInterface dialog,int id) {
						dialog.cancel();
					    }
					  });

				// create alert dialog
				AlertDialog alertDialog = alertDialogBuilder.create();

				// show it
				alertDialog.show();

			}
		});
	}
} 

3.演示

启动它,“main.xml”布局显示一个按钮和 edittext(结果)。

android prompt user input example

点击按钮,显示提示对话框“prompts.xml”布局,键入消息“ mkyong ”,并点击“确定”按钮。

android prompt user input example

用户输入“ mkyong ”将传递到“main.xml”布局,编辑文本(结果),并显示它。

android prompt user input example

下载源代码

Download it – Android-Prompt-Dialog-Example.zip (16 KB)

参考

  1. Android alert dialog Javadoc
  2. 安卓对话框示例
  3. Android 自定义对话框示例

Android 单选按钮示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-radio-buttons-example/

在 Android 中,可以使用“Android . widget . radio button类来渲染单选按钮,而那些单选按钮通常是由Android . widget . radio group分组的。如果RadioButtons在组中,当一个组中的一个RadioButton被选中时,所有其他的都被自动取消选中。

在本教程中,我们将向您展示如何使用 XML 创建两个单选按钮,并分组到一个单选按钮组中。单击按钮时,显示选中的单选按钮。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.自定义字符串

打开" res/values/strings.xml "文件,为单选按钮添加一些自定义字符串。

文件:res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, MyAndroidAppActivity!
    <string name="app_name">MyAndroidApp
    <string name="radio_male">Male
    <string name="radio_female">Female
    <string name="btn_display">Display
</resources> 

2.单选按钮

打开“ res/layout/main.xml 文件,在LinearLayout里面添加“ RadioGroup ”、“ RadioButton 和一个按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RadioGroup
        android:id="@+id/radioSex"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RadioButton
            android:id="@+id/radioMale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/radio_male" 
            android:checked="true" />

        <RadioButton
            android:id="@+id/radioFemale"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/radio_female" />

    </RadioGroup>

    <Button
        android:id="@+id/btnDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_display" />

</LinearLayout> 

Radio button selected by default.
To make a radio button is selected by default, put android:checked="true" within the RadioButton element. In this case, radio option “Male” is selected by default.

3.代码代码

在 activity " onCreate()"方法中,附加一个 click listener on 按钮。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

  private RadioGroup radioSexGroup;
  private RadioButton radioSexButton;
  private Button btnDisplay;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addListenerOnButton();

  }

  public void addListenerOnButton() {

	radioSexGroup = (RadioGroup) findViewById(R.id.radioSex);
	btnDisplay = (Button) findViewById(R.id.btnDisplay);

	btnDisplay.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {

		        // get selected radio button from radioGroup
			int selectedId = radioSexGroup.getCheckedRadioButtonId();

			// find the radiobutton by returned id
		        radioSexButton = (RadioButton) findViewById(selectedId);

			Toast.makeText(MyAndroidAppActivity.this,
				radioSexButton.getText(), Toast.LENGTH_SHORT).show();

		}

	});

  }
} 

4.演示

运行应用程序。

1.结果,选择了单选选项“男性”。

android radio button demo1

2.选择"女性"并点击"显示"按钮,所选择的单选按钮值被显示。

android radio button demo2

下载源代码

Download it – Android-RadioButton-Example.zip (15 KB)

参考

  1. Android RadioGroup JavaDoc
  2. 安卓单选按钮 JavaDoc
  3. Android RadioGroup 示例
  4. Android 单选按钮示例

Tags : android radio button

Android 评级栏示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-rating-bar-example/

在 Android 中,您可以使用“ android.widget.RatingBar ”在星星图标中显示评级栏组件。用户可以触摸、拖动或点击星星来轻松设置评级值。

在本教程中,我们向您展示了如何使用 XML 来显示一个评级栏,几个文本视图和一个按钮。当用户点击评级栏的星号时,所选的评级值将显示在文本视图中。并且,如果用户点击该按钮,所选择的评级值将显示为浮动消息(toast 消息)。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.分级栏

打开" res/layout/main.xml "文件,添加一个评级栏组件,几个 textviews 和一个按钮。

Note
The rating bar contains many configurable values. In this case, the rating bar contains 4 stars, each increase 1.0 value, so, it contains the minimum of 1.0 (1 star) and maximum value of 4.0 (4 stars). In addition, it made the 2nd star (2.0) selected by default.

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/lblRateMe"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Rate Me"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <RatingBar
        android:id="@+id/ratingBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:numStars="4"
        android:stepSize="1.0"
        android:rating="2.0" />

    <Button
        android:id="@+id/btnSubmit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Submit" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/lblResult"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Result : "
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/txtRatingValue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textAppearance="?android:attr/textAppearanceSmall" />

    </LinearLayout>

</LinearLayout> 

2.代码代码

在 activity " onCreate()"方法中,在评级栏上附加一个监听器,当评级值改变时触发。按钮上的另一个侦听器,在按钮被单击时触发。阅读代码的注释,应该是不言自明的。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RatingBar;
import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

  private RatingBar ratingBar;
  private TextView txtRatingValue;
  private Button btnSubmit;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addListenerOnRatingBar();
	addListenerOnButton();

  }

  public void addListenerOnRatingBar() {

	ratingBar = (RatingBar) findViewById(R.id.ratingBar);
	txtRatingValue = (TextView) findViewById(R.id.txtRatingValue);

	//if rating value is changed,
	//display the current rating value in the result (textview) automatically
	ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
		public void onRatingChanged(RatingBar ratingBar, float rating,
			boolean fromUser) {

			txtRatingValue.setText(String.valueOf(rating));

		}
	});
  }

  public void addListenerOnButton() {

	ratingBar = (RatingBar) findViewById(R.id.ratingBar);
	btnSubmit = (Button) findViewById(R.id.btnSubmit);

	//if click on me, then display the current rating value.
	btnSubmit.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {

			Toast.makeText(MyAndroidAppActivity.this,
				String.valueOf(ratingBar.getRating()),
					Toast.LENGTH_SHORT).show();

		}

	});

  }
} 

3.演示

运行应用程序。

1.结果,默认选择第二颗星。

android rating demo1

2.触摸第三颗星,额定值改变,在结果中显示当前选择的值(textview)。

android rating demo2

3.触摸第一个星号,点击提交按钮,当前选择值显示为浮动信息。

android rating demo3

下载源代码

Download it – Android-RatingBar-Example.zip (15 KB)

参考

  1. Android RatingBar JavaDoc
  2. 安卓分级栏示例

android rating

Android RelativeLayout 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-relativelayout-example/

在 Android 中, RelativeLayout 允许你根据附近(相对或兄弟)组件的位置来定位你的组件。这是最灵活的布局,允许你将你的组件放置在任何你想显示的地方(如果你知道如何“相对”它)。

RelativeLayout中,可以使用上方的下方的左侧的右侧的来排列组件的位置,例如在“按钮 2”下方显示一个“按钮 1”,或者在“按钮 1”的右侧显示“按钮 3”。

Note
The RelativeLayout is very flexible, but hard to master it. Suggest you use Eclipse IDE to drag the component, then view study the Eclipse generated XML layout code to understand how to code “relative” components.

在本教程中,我们将向您展示如何通过RelativeLayout来排列/定位buttontextvieweditbox

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.相对布局

打开“ res/layout/main.xml 文件,添加组件,通过“RelativeLayout定位。阅读下面的 XML 代码,非常详细地告诉你在哪里显示组件。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/btnButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"/>

    <Button
        android:id="@+id/btnButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 2"
        android:layout_toRightOf="@+id/btnButton1"/>

     <Button
        android:id="@+id/btnButton3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 3"
        android:layout_below="@+id/btnButton1"/>

     <TextView
         android:id="@+id/textView1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_below="@+id/btnButton3"
         android:layout_marginTop="94dp"
         android:text="User :"
         android:textAppearance="?android:attr/textAppearanceLarge" />

     <EditText
         android:id="@+id/editText1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
         android:layout_alignTop="@+id/textView1"
         android:layout_toRightOf="@+id/btnButton3" />

     <Button
         android:id="@+id/btnSubmit"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
         android:layout_below="@+id/editText1"
         android:text="Submit" />

</RelativeLayout> 

2.演示

请参见结果,上面的 XML 代码将生成以下输出。

android relativelayout demo ## 下载源代码

Download it – Android-RelativeLayout-Example.zip (15 KB)

参考

  1. Android RelativeLayout 示例
  2. Android relative layout JavaDoc

android layout relativelayout

Android 旋转器(下拉列表)示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-spinner-drop-down-list-example/

在 Android 中,可以使用“ android.widget.Spinner ”类来呈现下拉框选择列表。

Note
Spinner is a widget similar to a drop-down list for selecting items.

在本教程中,我们将向您展示如何执行以下任务:

  1. 用 XML 呈现一个微调器,并通过 XML 文件加载选择项。
  2. 用 XML 呈现另一个 Spinner,并通过代码动态加载选择项。
  3. 在 Spinner 上附加一个监听器,当用户在 Spinner 中选择一个值时触发。
  4. 在一个普通按钮上渲染并附加一个监听器,当用户点击它时触发,它将显示微调器的选定值。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.微调器中的项目列表

打开" res/values/strings.xml "文件,定义将在微调器中显示的项目列表(下拉列表)。

文件:res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">MyAndroidApp
    <string name="country_prompt">Choose a country

    <string-array name="country_arrays">
        <item>Malaysia</item>
        <item>United States</item>
        <item>Indonesia</item>
        <item>France</item>
        <item>Italy</item>
        <item>Singapore</item>
        <item>New Zealand</item>
        <item>India</item>
    </string-array>

</resources> 

2.微调器(下拉列表)

打开" res/layout/main.xml "文件,添加两个微调器组件和一个按钮。

  1. 在“spinner1”中,“android:entries”代表微调器中的选择项。
  2. 在“spinner2”中,选择项将在后面的代码中定义。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Spinner
        android:id="@+id/spinner1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/country_arrays"
        android:prompt="@string/country_prompt" />

    <Spinner
        android:id="@+id/spinner2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btnSubmit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Submit" />

</LinearLayout> 

3.代码代码

阅读代码和代码的注释,它应该是不言自明的。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

  private Spinner spinner1, spinner2;
  private Button btnSubmit;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addItemsOnSpinner2();
	addListenerOnButton();
	addListenerOnSpinnerItemSelection();
  }

  // add items into spinner dynamically
  public void addItemsOnSpinner2() {

	spinner2 = (Spinner) findViewById(R.id.spinner2);
	List<String> list = new ArrayList<String>();
	list.add("list 1");
	list.add("list 2");
	list.add("list 3");
	ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
		android.R.layout.simple_spinner_item, list);
	dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
	spinner2.setAdapter(dataAdapter);
  }

  public void addListenerOnSpinnerItemSelection() {
	spinner1 = (Spinner) findViewById(R.id.spinner1);
	spinner1.setOnItemSelectedListener(new CustomOnItemSelectedListener());
  }

  // get the selected dropdown list value
  public void addListenerOnButton() {

	spinner1 = (Spinner) findViewById(R.id.spinner1);
	spinner2 = (Spinner) findViewById(R.id.spinner2);
	btnSubmit = (Button) findViewById(R.id.btnSubmit);

	btnSubmit.setOnClickListener(new OnClickListener() {

	  @Override
	  public void onClick(View v) {

	    Toast.makeText(MyAndroidAppActivity.this,
		"OnClickListener : " + 
                "\nSpinner 1 : "+ String.valueOf(spinner1.getSelectedItem()) + 
                "\nSpinner 2 : "+ String.valueOf(spinner2.getSelectedItem()),
			Toast.LENGTH_SHORT).show();
	  }

	});
  }
} 

文件:CustomOnItemSelectedListener.java

 package com.mkyong.android;

import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Toast;

public class CustomOnItemSelectedListener implements OnItemSelectedListener {

  public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
	Toast.makeText(parent.getContext(), 
		"OnItemSelectedListener : " + parent.getItemAtPosition(pos).toString(),
		Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onNothingSelected(AdapterView<?> arg0) {
	// TODO Auto-generated method stub
  }

} 

4.演示

运行应用程序。

1.结果,显示两个微调器:

android spinner demo1android spinner demo2

2.从 spinner1 中选择“法国”,项目选择监听器被触发:

android spinner demo3

3.从微调器 2 中选择“list2 ”,然后单击提交按钮:

android spinner demo4

下载源代码

Download it – Android-Spinner-DropDownList-Example.zip (16 KB)

参考

  1. Android Spinner JavaDoc
  2. 安卓旋转器示例

Android 表格布局示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-tablelayout-example/

在 Android 中, TableLayout 让你按行和列排列组件,就像 HTML 中的标准表格布局,<tr><td>

在本教程中,我们将向您展示如何使用TableLayout来排列按钮、文本视图和以行和列的格式编辑文本,还将演示如何使用android:layout_span在两个单元格中显示视图,以及使用android:layout_column在指定的列中显示视图。

Note
In Eclipse 3.7, XML code assist will not prompts the attribute “android:layout_span“, “android:layout_column” and many other useful TableLayout attributes, no idea why, may be bug. Just put the attribute inside, it’s still compile and run.

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.表格布局

打开" res/layout/main.xml "文件,添加以下视图进行演示。阅读 XML 注释,它应该是不言自明的。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tableLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <!-- 2 columns -->
    <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <TextView
            android:id="@+id/textView1"
            android:text="Column 1"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <Button
            android:id="@+id/button1"
            android:text="Column 2" />
    </TableRow>

    <!-- edittext span 2 column -->
    <TableRow
        android:id="@+id/tableRow2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <EditText
            android:id="@+id/editText1"
            android:layout_span="2"
            android:text="Column 1 & 2" />
    </TableRow>

    <!-- just draw a red line -->
    <View
        android:layout_height="2dip"
        android:background="#FF0000" />

    <!-- 3 columns -->
    <TableRow
        android:id="@+id/tableRow3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <TextView
            android:id="@+id/textView2"
            android:text="Column 1"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <Button
            android:id="@+id/button2"
            android:text="Column 2" />

        <Button
            android:id="@+id/button3"
            android:text="Column 3" />
    </TableRow>

    <!-- display this button in 3rd column via layout_column(zero based) -->
    <TableRow
        android:id="@+id/tableRow4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <Button
            android:id="@+id/button4"
            android:layout_column="2"
            android:text="Column 3" />
    </TableRow>

    <!-- display this button in 2nd column via layout_column(zero based) -->
    <TableRow
        android:id="@+id/tableRow5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dip" >

        <Button
            android:id="@+id/button5"
            android:layout_column="1"
            android:text="Column 2" />
    </TableRow>

</TableLayout> 

2.演示

见结果。

android tablelayout demo ## 下载源代码

Download it – Android-TableLayout-Example.zip (15 KB)

参考

  1. Android 表格布局示例
  2. Android table layout JavaDoc
  3. 另一个很棒的 Android 表格布局示例
  4. 通过代码设置布局跨度

android layout tablelayout

Android 文本框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-textbox-example/

在 Android 中,你可以使用" EditText "类来创建一个可编辑的 textbox 来接受用户输入。

这个教程向你展示了如何在 XML 文件中创建一个 textbox,并演示了如何使用 key listener 来显示在 textbox 中输入的消息。

这个项目是在 Eclipse 中开发的,在 Android 2.3.3 中测试过。

1. EditText

打开“ res/layout/main.xml 文件,添加一个“ EditText 组件。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <requestFocus />

    </EditText>

</LinearLayout> 

2.编辑文本监听器

在 activity " onCreate()"方法中附加一个关键监听器,以监视以下事件:

  1. 如果按下“enter ”,显示一个浮动框,并在“EditText”框中键入消息。
  2. 如果按下“数字 9”,显示一个浮动框,并显示消息“数字 9 已按下!”。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.Toast;

public class MyAndroidAppActivity extends Activity {

 private EditText edittext;

 @Override
 public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addKeyListener();
 }

 public void addKeyListener() {

	// get edittext component
	edittext = (EditText) findViewById(R.id.editText);

	// add a keylistener to keep track user input
	edittext.setOnKeyListener(new OnKeyListener() {
	public boolean onKey(View v, int keyCode, KeyEvent event) {

		// if keydown and "enter" is pressed
		if ((event.getAction() == KeyEvent.ACTION_DOWN)
			&& (keyCode == KeyEvent.KEYCODE_ENTER)) {

			// display a floating message
			Toast.makeText(MyAndroidAppActivity.this,
				edittext.getText(), Toast.LENGTH_LONG).show();
			return true;

		} else if ((event.getAction() == KeyEvent.ACTION_DOWN)
			&& (keyCode == KeyEvent.KEYCODE_9)) {

			// display a floating message
			Toast.makeText(MyAndroidAppActivity.this,
				"Number 9 is pressed!", Toast.LENGTH_LONG).show();
			return true;
		}

		return false;
	}
 });
}
} 

3.演示

运行应用程序。

1.在文本框中键入一些内容,然后按“enter”键:

android textbox demo1

2.如果按下“数字 9”键:

android textbox demo2

下载源代码

Download it – Android-EditText-Example.zip (15 KB)

参考

  1. Android EditText JavaDoc
  2. Android EditText 示例

Android:与 adb 的连接中断,出现严重错误。

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-the-connection-to-adb-is-down-and-a-severe-error-has-occurred/

问题

使用 Eclipse IDE 进行 Android 开发时,有时会出现以下“ adb ”错误消息,导致应用程序无法启动?

 [2011-11-22 15:17:07 - HelloWorld] ------------------------------
[2011-11-22 15:17:07 - HelloWorld] Android Launch!
[2011-11-22 15:17:07 - HelloWorld] The connection to adb is down, and a severe error has occured.
[2011-11-22 15:17:07 - HelloWorld] You must restart adb and Eclipse.
[2011-11-22 15:17:07 - HelloWorld] Please ensure that adb is correctly located at 
   'C:\Android\android-sdk\platform-tools\adb.exe' and can be executed. 

P.S 重启 Eclipse 不会摆脱错误信息。

解决办法

在某些情况下,Android 项目可能会崩溃或异常关闭,并导致“adb.exe功能异常。

要解决这个问题,只需重启“adb.exe”进程。重启 Eclipse 不会自动关闭“【adb.exe】”进程,你需要手动杀死它。

比如,在 Windows 中,只需使用任务管理器来终止进程。

adb.exe errorandroid (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190310101843/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Android 时间选择器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-time-picker-example/

在 Android 中,您可以使用"Android . widget . time picker"类来呈现时间选择器组件,以便在预定义的用户界面中选择小时和分钟。

在本教程中,我们将向您展示如何通过Android . widget . time picker在当前页面中呈现时间选择器组件,以及通过Android . app . time picker dialog在对话框中呈现时间选择器组件。此外,我们还向您展示了如何设置时间选择器组件中的小时和分钟。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.时间选择器

打开“ res/layout/main.xml ”文件,添加时间选择器、标签和按钮进行演示。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnChangeTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change Time" />

    <TextView
        android:id="@+id/lblTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Current Time (H:M): "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/tvTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TimePicker
        android:id="@+id/timePicker1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout> 

"TimePickerDialog"是在代码中声明,而不是在 XML 中。

2.代码代码

阅读代码的注释,应该是不言自明的。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import java.util.Calendar;
import android.app.Activity;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;

public class MyAndroidAppActivity extends Activity {

	private TextView tvDisplayTime;
	private TimePicker timePicker1;
	private Button btnChangeTime;

	private int hour;
	private int minute;

	static final int TIME_DIALOG_ID = 999;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		setCurrentTimeOnView();
		addListenerOnButton();

	}

	// display current time
	public void setCurrentTimeOnView() {

		tvDisplayTime = (TextView) findViewById(R.id.tvTime);
		timePicker1 = (TimePicker) findViewById(R.id.timePicker1);

		final Calendar c = Calendar.getInstance();
		hour = c.get(Calendar.HOUR_OF_DAY);
		minute = c.get(Calendar.MINUTE);

		// set current time into textview
		tvDisplayTime.setText(
                    new StringBuilder().append(pad(hour))
                                       .append(":").append(pad(minute)));

		// set current time into timepicker
		timePicker1.setCurrentHour(hour);
		timePicker1.setCurrentMinute(minute);

	}

	public void addListenerOnButton() {

		btnChangeTime = (Button) findViewById(R.id.btnChangeTime);

		btnChangeTime.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				showDialog(TIME_DIALOG_ID);

			}

		});

	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case TIME_DIALOG_ID:
			// set time picker as current time
			return new TimePickerDialog(this, 
                                        timePickerListener, hour, minute,false);

		}
		return null;
	}

	private TimePickerDialog.OnTimeSetListener timePickerListener = 
            new TimePickerDialog.OnTimeSetListener() {
		public void onTimeSet(TimePicker view, int selectedHour,
				int selectedMinute) {
			hour = selectedHour;
			minute = selectedMinute;

			// set current time into textview
			tvDisplayTime.setText(new StringBuilder().append(pad(hour))
					.append(":").append(pad(minute)));

			// set current time into timepicker
			timePicker1.setCurrentHour(hour);
			timePicker1.setCurrentMinute(minute);

		}
	};

	private static String pad(int c) {
		if (c >= 10)
		   return String.valueOf(c);
		else
		   return "0" + String.valueOf(c);
	}
} 

另外,上面的“时间选择器对话框”的例子是从谷歌安卓时间选择器的例子中引用的,有一些小的变化。

3.演示

运行应用程序。

1.结果,“时间选择器”和“文本视图”被设置为当前时间。

android timepicker demo1

2.点击“更改时间”按钮,将通过TimePickerDialog在对话框中提示一个时间选择器组件。

android timepicker demo2

3.“时间选择器”和“文本视图”都用选定的时间更新。

android timepicker demo3

下载源代码

Download it – Android-TimePicker-Example.zip (16 KB)

参考

  1. Android 时间选择器示例
  2. Android TimePicker JavaDoc
  3. Android time picker dialog JavaDoc

Android 吐司示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-toast-example/

在 Android 中,Toast是一个弹出通知消息,显示一定的时间,并自动淡入淡出,大多数人只是用它来调试。

创建Toast消息的代码片段:

 //display in short period of time
Toast.makeText(getApplicationContext(), "msg msg", Toast.LENGTH_SHORT).show();

//display in long period of time
Toast.makeText(getApplicationContext(), "msg msg", Toast.LENGTH_LONG).show(); 

在本教程中,我们将向您展示两个Toast示例:

  1. 普通吐司视图。
  2. 自定义吐司视图。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.普通吐司视图

简单的Toast例子。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonToast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Toast" />

</LinearLayout> 

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonToast);

		button.setOnClickListener(new OnClickListener() {

			  @Override
			  public void onClick(View arg0) {

			     Toast.makeText(getApplicationContext(), 
                               "Button is clicked", Toast.LENGTH_LONG).show();

			  }
		});
	}
} 

看到演示,当一个按钮被点击,显示一个正常的祝酒辞信息。

android toast example

2.自定义吐司视图

通过自定义原来的Toast视图来增强上面的例子。

File:RES/layout/custom _ toast . XML–这是自定义 Toast 视图。

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_toast_layout_id"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#FFF"
    android:orientation="horizontal"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_marginRight="5dp" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:textColor="#000" />

</LinearLayout> 

文件:MainActivity.java–读取注释,获取上面的自定义视图并附加到Toast

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private Button button;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonToast);

		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				// get your custom_toast.xml ayout
				LayoutInflater inflater = getLayoutInflater();

				View layout = inflater.inflate(R.layout.custom_toast,
				  (ViewGroup) findViewById(R.id.custom_toast_layout_id));

				// set a dummy image
				ImageView image = (ImageView) layout.findViewById(R.id.image);
				image.setImageResource(R.drawable.ic_launcher);

				// set a message
				TextView text = (TextView) layout.findViewById(R.id.text);
				text.setText("Button is clicked!");

				// Toast...
				Toast toast = new Toast(getApplicationContext());
				toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
				toast.setDuration(Toast.LENGTH_LONG);
				toast.setView(layout);
				toast.show();
			}
		});
	}
} 

参见演示,当一个按钮被点击时,显示自定义的 Toast 消息。

Android Toast example

下载源代码

Download it – Android-Toast-Example.zip (16 KB)

参考

  1. 安卓吐司示例
  2. Android Toast JavaDoc

Android ToggleButton 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-togglebutton-example/

在 Android 中,“Android . widget . toggle button是一个特殊的类,用于呈现只有两种状态的按钮,例如“开”和“关”。它是单选按钮打开或关闭功能的最佳选择。

在本教程中,我们将向您展示如何使用 XML 创建两个切换按钮和一个普通按钮,当用户单击普通按钮时,它将显示两个切换按钮的当前状态。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.自定义字符串

打开" res/values/strings.xml "文件,为切换按钮添加一些自定义字符串。

文件:res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MyAndroidApp
    <string name="toggle_turn_on">Turn On
    <string name="toggle_turn_off">Turn Off
    <string name="btn_display">Display
</resources> 

2.切换按钮

打开“ res/layout/main.xml 文件,在LinearLayout里面添加两个“ ToggleButton 和一个普通按钮。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ToggleButton
        android:id="@+id/toggleButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ToggleButton" />

    <ToggleButton
        android:id="@+id/toggleButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="@string/toggle_turn_on"
        android:textOff="@string/toggle_turn_off"
        android:checked="true" />

    <Button
        android:id="@+id/btnDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/btn_display" />

</LinearLayout> 

Note
Review the “togglebutton2”, we did customized the togglebutton2’s display text on and off and made it checked by default. ## 3.代码代码

在 activity " onCreate()"方法内部,在一个普通按钮上附加一个 click 监听器,以显示切换按钮的当前状态。

文件:MyAndroidAppActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.widget.ToggleButton;

public class MyAndroidAppActivity extends Activity {

  private ToggleButton toggleButton1, toggleButton2;
  private Button btnDisplay;

  @Override
  public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	addListenerOnButton();

  }

  public void addListenerOnButton() {

	toggleButton1 = (ToggleButton) findViewById(R.id.toggleButton1);
	toggleButton2 = (ToggleButton) findViewById(R.id.toggleButton2);
	btnDisplay = (Button) findViewById(R.id.btnDisplay);

	btnDisplay.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {

		   StringBuffer result = new StringBuffer();
		   result.append("toggleButton1 : ").append(toggleButton1.getText());
		   result.append("\ntoggleButton2 : ").append(toggleButton2.getText());

		   Toast.makeText(MyAndroidAppActivity.this, result.toString(),
			Toast.LENGTH_SHORT).show();

		}

	});

  }
} 

4.演示

运行应用程序。

1.结果,toggleButton2 使用自定义字符串,并且默认选中。

android togglebutton demo1

2.选中 toggleButton1 和未选中的 toggleButton2,并单击显示按钮,将显示两个切换按钮的当前状态。

android togglebutton demo2

下载源代码

Download it – Android-ToggleButton-Example.zip (15 KB)

参考

  1. Android toggle button JavaDoc
  2. Android ToggleButton 示例

android button

Android 教程

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/android-tutorial/

android-logo

Android ,移动设备(智能手机和平板电脑)开源操作系统,由谷歌领衔。Android SDK 提供了一套使用 Java 开发 Android 应用程序的工具和 API。所以,如果你懂 Java,Android 编程很容易🙂

在这一系列教程中,我们向你展示了基础教程的列表,让你轻松地开始 Android 程序。

Note
All Android tutorials are developed in Eclipse 3.7, and tested with Android 2.3.3.

这只是 Android 教程的初始版本,以后会继续发布更多。

1.快速启动

让您开始 Android 编程。

2.基本原则

一些安卓基础的东西。

3.用户界面控件

玩 Android UI 控件。

4.布局

玩 Android 布局控件。

5.常见问题

Android 中的一些常见问题。

参考

  1. 安卓开发者
  2. 安卓基础
  3. 安卓在维基百科

Tags : android tutorials

Android WebView 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-webview-example/

Android 的 WebView 允许你打开自己的窗口来查看 URL 或自定义 html 标记页面。

在本教程中,您将创建两个页面,一个页面有一个按钮,当您单击它时,它将导航到另一个页面,并在 WebView 组件中显示 URL“google.com”。

P.S 这个项目是在 Eclipse 3.7 中开发的,用 Android 2.3.3 测试过。

1.Android 布局文件

创建两个 Android 布局文件——“RES/layout/main . XML”和“ res/layout/webview.xml ”。

文件:res/layout/main.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonUrl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Go to http://www.google.com" />

</LinearLayout> 

文件:RES/layout/main . XML–WebView 示例

 <?xml version="1.0" encoding="utf-8"?>
<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/> 

2.活动

两个活动类,一个活动显示一个按钮,另一个活动显示带有预定义 URL 的WebView

文件:MainActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	private Button button;

	public void onCreate(Bundle savedInstanceState) {
		final Context context = this;

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		button = (Button) findViewById(R.id.buttonUrl);

		button.setOnClickListener(new OnClickListener() {

		  @Override
		  public void onClick(View arg0) {
		    Intent intent = new Intent(context, WebViewActivity.class);
		    startActivity(intent);
		  }

		});

	}

} 

文件:WebViewActivity.java

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class WebViewActivity extends Activity {

	private WebView webView;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.webview);

		webView = (WebView) findViewById(R.id.webView1);
		webView.getSettings().setJavaScriptEnabled(true);
		webView.loadUrl("http://www.google.com");

	}

} 

3.Android 清单

WebView所需的上网权限,添加到下面的AndroidManifest.xml中。

 <uses-permission android:name="android.permission.INTERNET" /> 

文件:Android manifest . XML–参见完整示例。

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mkyong.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".WebViewActivity"
            android:theme="@android:style/Theme.NoTitleBar" />

        <activity
            android:label="@string/app_name"
            android:name=".MainActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

4.演示

默认情况下,只显示一个按钮。

android webview example

点击按钮,显示 WebView。

android webview example

5.再次演示

WebView允许您通过webView.loadData()手动加载自定义 HTML 标记,参见修改后的版本:

 package com.mkyong.android;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class WebViewActivity extends Activity {

	private WebView webView;

	public void onCreate(Bundle savedInstanceState) {
	   super.onCreate(savedInstanceState);
	   setContentView(R.layout.webview);

	   webView = (WebView) findViewById(R.id.webView1);
	   webView.getSettings().setJavaScriptEnabled(true);
	   //webView.loadUrl("http://www.google.com");

	   String customHtml = "<html><body><h1>Hello, WebView</h1></body></html>";
	   webView.loadData(customHtml, "text/html", "UTF-8");

	}

} 

现在,当点击按钮时,会显示一个定制的 html 页面。

android webview example

下载源代码

Download it – Android-WebView-Example.zip (16 KB)

参考

  1. 官方 Android webView 示例
  2. Android WebView Javadoc
  3. 切换安卓活动

Tags : android webview

Android wrap_content 和 fill_parent 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/android-wrap_content-and-fill_parent-example/

在 Android 中,你总是在组件的属性“layout_width”和“【T3””上加上“wrap_content”或“fill_parent”,你不知道这有什么不同吗?

参见以下定义:

  1. wrap _ content–组件只想显示足够大的内容。
  2. fill _ parent–组件想要显示得和它的父组件一样大,并填充剩余的空间。(在 API 级别 8 中重命名为 match_parent)

以上术语现在可能没有意义,让我们看看下面的演示:

1.包装内容

一个按钮组件,在宽度和高度属性上都设置了“wrap_content”。它告诉 Android 只显示足够大的按钮来包含它的内容“按钮 ABC ”。

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/btnButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button ABC"/>

</RelativeLayout> 

android wrap-content example1

2.填充 _ 父级–宽度

将“layout_width”改为“【T1”),现在,按钮的宽度将填充剩余的空间,就像它的父“T2”一样大,但按钮的高度仍然足够大,只能包含它的内容。

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/btnButton1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Button ABC"/>

</RelativeLayout> 

android wrap-content example2

3.填充 _ 父级–高度

将“layout_height”改为“【T1”),现在,按钮的高度将填充剩余的空间,就像它的父“【T2”一样大,但按钮的宽度仍然足够大,只能包含它的内容。

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/btnButton1"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:text="Button ABC"/>

</RelativeLayout> 

android wrap-content example3

4.fill _ parent–宽度、高度

将“layout_width”和“layout_height”都改为“【T2”,按钮将显示为整个设备屏幕那么大,正好填满整个屏幕空间。

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:id="@+id/btnButton1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="Button ABC"/>

</RelativeLayout> 

android wrap-content example4Note
Actually, you can specifying an exact width and height, but it’s not recommended, due to Android variety of devices screen size. You just do not know what size of Android device is running your fantasy application.

参考

  1. Android XML 布局文档
  2. 安卓视图组。LayoutParams 文档

Ant 和 jUnit 任务示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-and-junit-task-example/

在本教程中,我们将向您展示如何在 Ant build 中运行 junit 测试。

junit tutorials

1.运行单元测试

build.xml

 <target name="junit" depends="compile">

    <junit printsummary="yes" haltonfailure="no">

	<!-- Project classpath, must include junit.jar -->
	<classpath refid="test.path" />

	<!-- test class -->
	<classpath location="${test.classes.dir}" />

	<test name="com.mkyong.test.TestMessage" 
		haltonfailure="no" todir="${report.dir}">
		<formatter type="plain" />
		<formatter type="xml" />
	</test>

  </junit>
</target> 

2.运行一批单元测试

build.xml

 <target name="junit" depends="compile">

  <junit printsummary="yes" haltonfailure="no">

	<!--
		<classpath location="lib/junit-4.11.jar" />
		<classpath location="lib/hamcrest-core-1.3.jar" />
	-->
	<classpath refid="test.path" />
	<classpath location="${test.classes.dir}" />

	<formatter type="xml" />
	<formatter type="plain" />

	<batchtest fork="yes" todir="${report.dir}">
		<fileset dir="${test.dir}">
			<include name="**/*Test*.java" />
		</fileset>
	</batchtest>

  </junit>
</target> 

3.例子

一个 web 应用程序示例,向您展示如何运行 junit 测试。

3.1 返回消息

MessageGenerator.java

 package com.mkyong.message;

import org.springframework.stereotype.Component;

@Component
public class MessageGenerator {

	public String getWelcomeMessage() {
		return "welcome"; 
	}

} 

3.2 测试上述类的两个 junit 测试用例。

TestMessage.java

 package com.mkyong.test;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.mkyong.message.MessageGenerator;

public class TestMessage {

	@Test
	public void test_welcome_message() {
		MessageGenerator obj = new MessageGenerator();
		assertEquals("welcome", obj.getWelcomeMessage());
	}

} 

TestMessage2.java

 package com.mkyong.test;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.mkyong.message.MessageGenerator;

public class TestMessage2 {

	@Test
	public void test_welcome_message_2() {
		MessageGenerator obj = new MessageGenerator();
		assertEquals("welcome", obj.getWelcomeMessage());
	}

} 

3.3 使用 ivy 获取项目依赖项,并声明项目范围。

ivy.xml

 <ivy-module version="2.0">
	<info organisation="org.apache" module="WebProject" />

	<configurations>
        <conf name="compile" description="Required to compile application"/>
        <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
        <conf name="test"    description="Required for test only" extends="runtime"/>
    </configurations>

	<dependencies>
		<dependency org="junit" name="junit" rev="4.11" conf="test->default" />
	</dependencies>
</ivy-module> 

3.4 运行单元测试

build.xml

 <project xmlns:ivy="antlib:org.apache.ivy.ant" 
	name="HelloProject" default="main" basedir=".">
	<description>
		Running junit Test 
	</description>

	<!-- Project Structure -->
	<property name="jdk.version" value="1.7" />
	<property name="projectName" value="WebProject" />
	<property name="src.dir" location="src" />
	<property name="test.dir" location="src" />
	<property name="report.dir" location="report" />
	<property name="web.dir" value="war" />
	<property name="web.classes.dir" location="${web.dir}/WEB-INF/classes" />

	<!-- ivy start -->
	<target name="resolve" description="retrieve dependencies with ivy">
		<echo message="Getting dependencies..." />
		<ivy:retrieve />

		<ivy:cachepath pathid="compile.path" conf="compile" />
		<ivy:cachepath pathid="runtime.path" conf="runtime" />
		<ivy:cachepath pathid="test.path" conf="test" />

	</target>

	<!-- Compile Java source from ${src.dir} and output it to ${web.classes.dir} -->
	<target name="compile" depends="init, resolve" description="compile source code">
		<mkdir dir="${web.classes.dir}" />
		<javac destdir="${web.classes.dir}" source="${jdk.version}" 
			target="${jdk.version}" debug="true" 
                        includeantruntime="false" classpathref="compile.path">
			<src path="${src.dir}" />
		</javac>
	</target>

	<!-- Run jUnit -->
	<target name="junit" depends="compile">

	  <junit printsummary="yes" haltonfailure="no">

		<classpath refid="test.path" />
		<classpath location="${web.classes.dir}" />

		<formatter type="xml" />
		<batchtest fork="yes" todir="${report.dir}">
			<fileset dir="${test.dir}">
				<include name="**/*Test*.java" />
			</fileset>
		</batchtest>

	  </junit>
	</target>

	<!-- Create folders -->
	<target name="init">
		<mkdir dir="${src.dir}" />
		<mkdir dir="${web.classes.dir}" />
		<mkdir dir="${report.dir}" />
	</target>

	<!-- Delete folders -->
	<target name="clean" description="clean up">
		<delete dir="${web.classes.dir}" />
		<delete dir="${report.dir}" />
	</target>

	<target name="main" depends="junit" />

</project>
Run it
<pre><code class="language-bash">
$ ant junit 

完成了。

下载源代码

Download It - AntSpringMVC-Junit-Example (42 KB)

参考

  1. Ant - junit 任务

ant junit unit test

Ant 和 TestNG 任务示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-and-testng-task-example/

testng tutorials

在本教程中,我们将向您展示如何在 Ant build 中运行 TestNG 测试。

1.按类运行

build.xml

 <taskdef name="testng" classname="org.testng.TestNGAntTask">
	<classpath location="lib/testng-6.8.14.jar" />
  </taskdef>

  <target name="testng" depends="compile">

	<!-- Assume test.path contains the project library dependencies -->
	<testng classpathref="test.path"
		outputDir="${report.dir}" 
		haltOnFailure="true">

		<!-- Extra project classpath, which is not included in above "test.path" -->
		<!-- Tell Ant where is the project and test classes -->
		<classpath location="${test.classes.dir}" />
		<classpath location="${src.classes.dir}" />

		<!-- Tell Ant what test classes need to run -->
		<classfileset dir="${test.classes.dir}" includes="**/*Test*.class" />

	</testng>

  </target> 

2.由 XML 运行

${resources.dir}/testng.xml

 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll">

    <test name="anyname">
	<classes>
		<class name="com.mkyong.test.TestMessage" />
	</classes>
    </test>

</suite> 

build.xml

 <taskdef name="testng" classname="org.testng.TestNGAntTask">
	<classpath location="lib/testng-6.8.14.jar" />
  </taskdef>

  <target name="testng" depends="compile">

	<testng classpathref="test.path"
		outputDir="${report.dir}" 
		haltOnFailure="true">

		<classpath location="${test.classes.dir}" />

		<!-- Tell Ant where is testng.xml -->
		<xmlfileset dir="${resources.dir}" includes="testng.xml"/>

	</testng>

  </target> 

3.例子

一个 web 应用程序示例,向您展示如何运行一组 TestNG 测试。

3.1 返回消息

MessageGenerator.java

 package com.mkyong.message;

import org.springframework.stereotype.Component;

@Component
public class MessageGenerator {

	public String getWelcomeMessage() {
		return "welcome"; 
	}

} 

3.2 两次测试。

TestMessage.java

 package com.mkyong.test;

import org.testng.Assert;
import org.testng.annotations.Test;
import com.mkyong.message.MessageGenerator;

public class TestMessage {

	@Test
	public void test_welcome_message() {
		MessageGenerator obj = new MessageGenerator();
		Assert.assertEquals(obj.getWelcomeMessage(), "welcome");
	}

} 

TestMessage2.java

 package com.mkyong.test;

import org.testng.Assert;
import org.testng.annotations.Test;
import com.mkyong.message.MessageGenerator;

public class TestMessage2 {

	@Test
	public void test_welcome_message_2() {
		MessageGenerator obj = new MessageGenerator();
		Assert.assertEquals(obj.getWelcomeMessage(), "welcome");
	}

} 

3.3 使用 ivy 获取项目依赖关系,并声明项目范围。

ivy.xml

 <ivy-module version="2.0">
	<info organisation="org.apache" module="WebProject" />

	<configurations>
        <conf name="compile" description="Required to compile application"/>
        <conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
        <conf name="test"    description="Required for test only" extends="runtime"/>
    </configurations>

	<dependencies>
		<dependency org="org.testng" name="testng" rev="6.8.14" conf="test->default" />
	</dependencies>
</ivy-module> 

3.4 运行单元测试

build.xml

 <project xmlns:ivy="antlib:org.apache.ivy.ant" 
	name="HelloProject" default="main" basedir=".">
	<description>
		Running TestNG Test 
	</description>

	<!-- Project Structure -->
	<property name="jdk.version" value="1.7" />
	<property name="projectName" value="WebProject" />
	<property name="src.dir" location="src" />
	<property name="test.dir" location="src" />
	<property name="report.dir" location="report" />
	<property name="web.dir" value="war" />
	<property name="web.classes.dir" location="${web.dir}/WEB-INF/classes" />

	<!-- ivy start -->
	<target name="resolve" description="retrieve dependencies with ivy">
		<echo message="Getting dependencies..." />
		<ivy:retrieve />

		<ivy:cachepath pathid="compile.path" conf="compile" />
		<ivy:cachepath pathid="runtime.path" conf="runtime" />
		<ivy:cachepath pathid="test.path" conf="test" />

	</target>

	<!-- Compile Java source from ${src.dir} and output it to ${web.classes.dir} -->
	<target name="compile" depends="init, resolve" description="compile source code">
		<mkdir dir="${web.classes.dir}" />
		<javac destdir="${web.classes.dir}" source="${jdk.version}" 
			target="${jdk.version}" debug="true" includeantruntime="false" classpathref="compile.path">
			<src path="${src.dir}" />
		</javac>
	</target>

	<!-- Run TestNG -->
	<target name="testng" depends="compile">

	  <testng classpathref="test.path"
		outputDir="${report.dir}" 
		haltOnFailure="true">

		<classpath location="${web.classes.dir}" />

		<xmlfileset dir="${resources.dir}" includes="testng.xml"/>

                <!--
		  <classfileset dir="${web.classes.dir}" includes="**/*Test*.class" />
		-->
	  </testng>

	</target>

	<!-- Create folders -->
	<target name="init">
		<mkdir dir="${src.dir}" />
		<mkdir dir="${web.classes.dir}" />
		<mkdir dir="${report.dir}" />
	</target>

	<!-- Delete folders -->
	<target name="clean" description="clean up">
		<delete dir="${web.classes.dir}" />
		<delete dir="${report.dir}" />
	</target>

	<target name="main" depends="testng" />

</project> 

${resources.dir}/testng.xml

 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll">

	<test name="example1">
		<classes>
			<class name="com.mkyong.test.TestMessage" />
			<class name="com.mkyong.test.TestMessage2" />
		</classes>
	</test>

</suite> 

运行它

 $ ant testng 

输出

 testng:
   [testng] [TestNG] Running:
   [testng]   /Users/mkyong/Documents/workspace/AntSpringMVC/resources/testng.xml
   [testng] 
   [testng] 
   [testng] ===============================================
   [testng] TestAll
   [testng] Total tests run: 2, Failures: 0, Skips: 0
   [testng] ===============================================
   [testng] 

BUILD SUCCESSFUL
Total time: 3 seconds 

完成了。

下载源代码

Download It – AntSpringMVC-TestNG-Example (90 KB)

参考

  1. Ant–TestNG 任务
  2. Ang 和 jUnit 任务
  3. TestNG–套件测试

如果不在 Ant 自己的类路径中,则必须包含 junit.jar

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-error-must-include-junit-jar-if-not-in-ants-own-classpath/

在 Ant 中声明一个 junit 任务,如下所示

build.xml

 <!-- Run jUnit -->
  <target name="junit" depends="resolve">

	<junit printsummary="yes" haltonfailure="no">

		<classpath refid="test.path" />
		<classpath location="${build.dir}" />

		<test name="com.mkyong.test.TestMessage" 
			haltonfailure="no" todir="${report.dir}" outfile="result">
			<formatter type="plain" />
			<formatter type="xml" />
		</test>

	</junit>
  </target> 

运行ant junit,但出现以下错误信息:

 BUILD FAILED
build.xml:86: The <classpath> for <junit> must include junit.jar if not in Ant's own classpath 

解决办法

要在 Ant 中运行 junit 任务,请确保在类路径中定义了junit.jar

build.xml

 <!-- Run jUnit -->
  <target name="junit" depends="resolve">

	<junit printsummary="yes" haltonfailure="no">

		<classpath refid="test.path" />
		<classpath location="${build.dir}" />

		<!-- Make sure these two libraries are included -->
		<classpath location="lib/junit-4.11.jar" />
		<classpath location="lib/hamcrest-core-1.3.jar" />

		<test name="com.mkyong.test.TestMessage" 
			haltonfailure="no" todir="${report.dir}" outfile="result">
			<formatter type="plain" />
			<formatter type="xml" />
		</test>

	</junit>
  </target> 

参考

  1. 蚂蚁 jUnit 任务
  2. Ant 常见问题:junit 忽略了我的类路径

ant——如何用外部库创建 Jar 文件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-how-to-create-a-jar-file-with-external-libraries/

在本教程中,我们将向您展示如何使用 Ant 构建脚本来创建 Jar 文件,以及如何使用项目的外部库/依赖项。

使用的技术:

  1. Eclipse 4.2
  2. JDK 1.7
  3. Ant 1.9.4
  4. 蚂蚁常春藤 2.4
  5. 回溯 1.1.2
  6. joda-时间 2.5

P.S 之前的 Ant Java 项目将被重用。

1.项目结构

图 1.1:最终的项目目录结构,在 Eclipse IDE 中。

ant-external-libraries-final

2.Java 项目+外部库

在 Eclipse IDE 中,重新打开之前的 Java 项目 AntDateUtils ,更新源代码使用logbackjoda-time

src/com/mkyong/core/utils/DateUtils.java

 package com.mkyong.core.utils;

import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DateUtils {

	private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);

	public static void main(String[] args) {

		logger.debug("[MAIN] Current Date : {}", getLocalCurrentDate());
		System.out.println(getLocalCurrentDate());

	}

	private static String getLocalCurrentDate() {

		LocalDate date = new LocalDate();
		return date.toString();

	}

} 

创建一个logback.xml并把它放在项目src文件夹中。参见图 1.1

src/logback.xml

 <?xml version="1.0" encoding="UTF-8"?>
<configuration>

	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
	  <layout class="ch.qos.logback.classic.PatternLayout">

		<Pattern>
			ANT + LogBack : %-5level %logger{36} - %msg%n
		</Pattern>

	  </layout>
	</appender>

	<root level="debug">
	  <appender-ref ref="STDOUT" />
	</root>

</configuration> 

3.ivy–获取外部库

我们使用 Apache Ivy 来获取项目的外部库/依赖项。

3.1 创建该文件ivy.xml:

ivy.xml

 <ivy-module version="2.0">
	<info organisation="org.apache" module="dateUtilsProject" />
	<dependencies>
		<dependency org="joda-time" name="joda-time" rev="2.5"  />
		<dependency org="org.slf4j" name="slf4j-api" rev="1.7.6" />
		<dependency org="ch.qos.logback" name="logback-classic" rev="1.1.2" />
	</dependencies>
</ivy-module> 

3.2 更新build.xml,在顶部添加 ivy 名称空间,以及下载 ivy 模块的“ivy”任务,以及要求 Ivy 模块下载外部库的“resolve”任务。

build.xml

 <project xmlns:ivy="antlib:org.apache.ivy.ant" 
	name="dateUtilsProject" default="main" basedir=".">

	<!-- ivy start -->
	<!-- ivy to get dependencies and copy to project lib folder automatically -->
	<target name="resolve" description="retrieve dependencies with ivy">
		<ivy:retrieve />
	</target>

	<!-- install ivy -->
	<target name="ivy" description="Install ivy">
		<mkdir dir="${user.home}/.ant/lib" />
		<get dest="${user.home}/.ant/lib/ivy.jar" 
			src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0-rc1/ivy-2.4.0-rc1.jar" />
	</target>
	<!-- ivy end -->

</project> 

第一次,从 Maven center 资源库下载 ivy 模块到本地${user.home}/.ant/lib/ivy.jar

 $ ant ivy 

要下载外部库,请运行任务“解决”。声明的库将被下载到项目lib文件夹。

 $ ant resolve 

4.build.xml

查看更新后的build.xml脚本,阅读注释以了解自明性。

要点:

  1. 使用 Apache Ivy 管理项目外部库,检查顶层的 Ivy 名称空间,并执行“resolve”任务。
  2. 要编译源代码,您需要声明类路径。查看任务“编译”和“classpathref”属性。
  3. 在“jar”任务中,构建外部库的完整列表,并将其放入manifest.mf文件中。
  4. 在“jar”任务中,项目 jar 将被打包到文件夹“dist ”,整个外部库将被从“lib”复制到“dist/lib”。

build.xml

 <project xmlns:ivy="antlib:org.apache.ivy.ant" 
       name="dateUtilsProject" default="main" basedir=".">
	<description>
		Create a Java Project (JAR) with Ant build script
	</description>

	<property name="projectName" value="DateUtils" />
	<property name="src.dir" location="src" />
	<property name="build.dir" location="bin" />
	<property name="dist.dir" location="dist" />
	<property name="dist.lib.dir" location="dist/lib" />
	<property name="lib.dir" value="lib" />
	<property name="main-class" value="com.mkyong.core.utils.DateUtils" />

	<!-- ivy start -->
	<!-- ivy to get dependencies and copy to project lib folder automatically -->
	<target name="resolve" description="retrieve dependencies with ivy">
		<ivy:retrieve />
	</target>

	<!-- install ivy -->
	<target name="ivy" description="Install ivy">
		<mkdir dir="${user.home}/.ant/lib" />
		<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0-rc1/ivy-2.4.0-rc1.jar" />
	</target>
	<!-- ivy end -->

	<target name="init">
		<mkdir dir="${build.dir}" />
	</target>

	<!-- external libraries classpath, we don't need sources and javadoc -->
	<path id="classpath">
		<fileset dir="${basedir}/">
			<include name="${lib.dir}/*.jar" />
			<exclude name="${lib.dir}/*sources.jar"/>
			<exclude name="${lib.dir}/*javadoc.jar"/>
		</fileset>
	</path>

	<!-- To work with external libraries, need classpath to compile -->
	<target name="compile" depends="init" description="compile the source ">
		<javac includeantruntime="false" srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath" />
	</target>

	<!-- constructs the external libraries classpath name -->
	<pathconvert property="classpath.name" pathsep=" ">
		<path refid="classpath" />
		<mapper>
			<chainedmapper>
				<flattenmapper />
				<globmapper from="*.jar" to="lib/*.jar" />
			</chainedmapper>
		</mapper>
	</pathconvert>

	<target name="copy-dependencies">
		<copy todir="${dist.lib.dir}">
			<fileset dir="${lib.dir}" includes="**/*.jar" excludes="**/*sources.jar, **/*javadoc.jar" />
		</copy>
	</target>

	<!-- jar it, and declares the ext libraries in manifest.mf file -->
	<target name="jar" depends="compile, copy-dependencies" description="package, output to JAR">

		<echo message="classpath.name : ${classpath.name} " />

		<mkdir dir="${dist.dir}" />
		<mkdir dir="${dist.lib.dir}" />

		<jar jarfile="${dist.dir}/${projectName}.jar" basedir="${build.dir}">
			<manifest>
				<attribute name="Main-Class" value="${main-class}" />
				<attribute name="Class-Path" value="${classpath.name}" />
			</manifest>
		</jar>
	</target>

	<target name="clean" description="clean up">
		<delete dir="${build.dir}" />
		<delete dir="${dist.dir}" />
	</target>

	<!-- Default, run this -->
	<target name="main" depends="clean, compile, jar" />

</project> 

5.试验

用 Ant 构建脚本测试 Java 项目。

5.1 装罐。

 $ pwd
/Users/mkyong/Documents/workspace/AntDateUtils

$ ant
Buildfile: /Users/mkyong/Documents/workspace/AntDateUtils/build.xml

clean:
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/bin
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/dist

init:
    [mkdir] Created dir: /Users/mkyong/Documents/workspace/AntDateUtils/bin

compile:
    [javac] Compiling 1 source file to /Users/mkyong/Documents/workspace/AntDateUtils/bin

copy-dependencies:
     [copy] Copying 12 files to /Users/mkyong/Documents/workspace/AntDateUtils/dist/lib

jar:
     [echo] classpath.name : ... lib/joda-time-2.5.jar lib/logback-classic-1.1.2.jar lib/logback-core-1.1.2.jar lib/mail-1.4.jar ...

      [jar] Building jar: /Users/mkyong/Documents/workspace/AntDateUtils/dist/DateUtils.jar

main:

BUILD SUCCESSFUL
Total time: 1 second 

5.2 检查生成的 jar 文件。

 $ jar -tf dist/DateUtils.jar 

META-INF/
META-INF/MANIFEST.MF
com/
com/mkyong/
com/mkyong/core/
com/mkyong/core/utils/
com/mkyong/core/utils/DateUtils.class 

META-INF/MANIFEST.MF

 Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.4
Created-By: 1.7.0_05-b05 (Oracle Corporation)
Main-Class: com.mkyong.core.utils.DateUtils
Class-Path: lib/activation-1.1.jar lib/commons-compiler-2.6.1.jar lib/
 geronimo-jms_1.1_spec-1.0.jar lib/groovy-all-2.0.7.jar lib/janino-2.6
 .1.jar lib/joda-convert-1.2.jar lib/joda-time-2.5.jar lib/logback-cla
 ssic-1.1.2.jar lib/logback-core-1.1.2.jar lib/mail-1.4.jar lib/servle
 t-api-2.5.jar lib/slf4j-api-1.7.6.jar 

5.3 运行 Jar 文件。

 $ pwd
/Users/mkyong/Documents/workspace/AntDateUtils

$ java -jar dist/DateUtils.jar 

16:28:43.957 [main] DEBUG com.mkyong.core.utils.DateUtils - [MAIN] Current Date : 2014-11-21
2014-11-21 

5.4 用logback.xml再次运行 Jar 文件。

 $ pwd
/Users/mkyong/Documents/workspace/AntDateUtils

$ java -jar -Dlogback.configurationFile=src/logback.xml dist/DateUtils.jar

16:34:43,746 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [src/logback.xml] at [file:/Users/mkyong/Documents/workspace/AntDateUtils/src/logback.xml]
//...

ANT + LogBack : DEBUG com.mkyong.core.utils.DateUtils - [MAIN] Current Date : 2014-11-21
2014-11-21 

下载源代码

Download it – AntDateUtils-External-Libraries.zip (8 KB)

参考

  1. 阿帕奇蚂蚁 Hello 世界官方指南
  2. 如何用 Maven 创建 Jar 文件
  3. 蚂蚁罐子任务
  4. 蚂蚁复制任务

ant——如何创建 Java 项目

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-how-to-create-a-java-project/

在本教程中,我们将向您展示如何使用 Ant 构建工具来管理 Java 项目、编译并将其打包到 Jar 文件中。

使用的技术:

  1. Eclipse 4.2
  2. Ant 1.9.4
  3. JDK 1.7

1.创建一个 Java 项目

在 Eclipse IDE 中,创建一个名为“AntDateUtils”的新 Java 项目。

ant-java-project

2.Java 源代码

创建一个新的 Java 类来打印当前日期:

src/com/mkyong/core/utils/DateUtils.java

 package com.mkyong.core.utils;

import java.util.Date;

public class DateUtils {

	public static void main(String[] args) {

		System.out.println(getLocalCurrentDate());

	}

	private static Date getLocalCurrentDate() {
		return new Date();		
	}

} 

3.build.xml

在项目根文件夹中创建一个新的build.xml,阅读注释进行自我解释。

build.xml

 <project name="AntJavaProject" default="main" basedir=".">
	<description>
		Create a Java Project (JAR) with Ant build script
	</description>

	<property name="projectName" value="DateUtils" />

	<!-- Java sources -->
	<property name="src.dir" location="src" />

	<!-- Java classes -->
	<property name="build.dir" location="bin" />

	<!-- Output, Jar -->
	<property name="dist.dir" location="dist" />

	<target name="init">
		<!-- Create the time stamp -->
		<tstamp />
		<!-- Create the build directory structure used by compile -->
		<mkdir dir="${build.dir}" />
	</target>

	<target name="compile" depends="init" description="compile the source ">
		<!-- Compile the java code from ${src.dir} into ${build.dir} -->
		<javac includeantruntime="false" srcdir="${src.dir}" destdir="${build.dir}" />
	</target>

	<target name="dist" depends="compile" description="package, output to JAR">

		<!-- Create the distribution directory -->
		<mkdir dir="${dist.dir}" />

		<!-- Put everything in ${build} into the {$projectName}-${DSTAMP}.jar file -->
		<jar jarfile="${dist.dir}/${projectName}-${DSTAMP}.jar" basedir="${build.dir}" >
		    <manifest>
			<!-- create an executable Jar -->
			<attribute name="Main-Class" value="com.mkyong.core.utils.DateUtils" />
		    </manifest>
		</jar>
	</target>

	<target name="clean" description="clean up">
		<delete dir="${build.dir}" />
		<delete dir="${dist.dir}" />
	</target>

	<!-- Default, run this -->
	<target name="main" depends="clean, compile, dist" />

</project> 

4.Ant 构建脚本

完成后,尝试几个 Ant 的命令

4.1 编译源代码

 $ ant compile 

build.xml

 <target name="compile" depends="init" description="compile the source ">
	<javac includeantruntime="false" srcdir="${src.dir}" destdir="${build.dir}" />
</target> 

4.2 将项目打包成一个可执行的 Jar 文件

 $ ant dist 

build.xml

 <target name="dist" depends="compile" description="package, output to JAR">
	<mkdir dir="${dist.dir}" />
	<jar jarfile="${dist.dir}/${projectName}-${DSTAMP}.jar" basedir="${build.dir}">
	  <manifest>
		<attribute name="Main-Class" value="com.mkyong.core.utils.DateUtils" />
	  </manifest>
	</jar>
</target> 

4.3 删除文件夹

 $ ant clean 

build.xml

 <target name="clean" description="clean up">
	<delete dir="${build.dir}" />
	<delete dir="${dist.dir}" />
</target> 

4.4 如果没有选项,默认目标将被执行,在本例中,默认目标是main

build.xml

 <project name="AntJavaProject" default="main" basedir=".">
	...
	<target name="main" depends="clean, compile, dist" /> 
 $ ant 

输出

 Buildfile: /Users/mkyong/Documents/workspace/AntDateUtils/build.xml
clean:
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/bin
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntDateUtils/dist
init:
    [mkdir] Created dir: /Users/mkyong/Documents/workspace/AntDateUtils/bin
compile:
    [javac] Compiling 1 source file to /Users/mkyong/Documents/workspace/AntDateUtils/bin
dist:
    [mkdir] Created dir: /Users/mkyong/Documents/workspace/AntDateUtils/dist
      [jar] Building jar: /Users/mkyong/Documents/workspace/AntDateUtils/dist/DateUtils-20141030.jar
main:
BUILD SUCCESSFUL
Total time: 1 second 

最终目录结构

ant-java-project-final

5.试验

5.1 在 Jar 文件中运行一个类。

 $ pwd
/Users/mkyong/Documents/workspace/AntDateUtils

$ java -cp dist/DateUtils-20141030.jar com.mkyong.core.utils.DateUtils
Thu Oct 30 17:39:21 MYT 2014 

5.2 运行可执行的 Jar 文件

 $ pwd
/Users/mkyong/Documents/workspace/AntDateUtils

$ java -jar dist/DateUtils-20141030.jar
Thu Oct 30 17:40:21 MYT 2014 

下载源代码

Download It – AntDateUtils.zip (6 KB)

参考

  1. 阿帕奇蚂蚁 Hello 世界官方指南

ant——如何从路径 id 打印类路径

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-how-to-print-classpath-from-path-id/

在 Ant 中,可以使用pathconvert任务从 path 中打印出类路径:

build.xml

 <path id="project.web.classpath">
	<pathelement location="test/lib/junit-4.11.jar"/>
	<pathelement location="test/lib/hamcrest-core-1.3.jar"/>

	<fileset dir="${lib.web.dir}">
		<include name="**/*.jar" />
	</fileset>	
  </path>

  <target name="print-classpath">

	<pathconvert property="classpathInName" refid="project.web.classpath" />
	<echo>Classpath is ${classpathInName}</echo>

  </target> 

测试:

 $ ant print-classpath
Buildfile: /Users/mkyong/Documents/workspace/AntSpringMVC/build.xml

print-classpath:

     [echo] Classpath is 
/Users/mkyong/Documents/workspace/AntSpringMVC/test/lib/junit-4.11.jar:
/Users/mkyong/Documents/workspace/AntSpringMVC/testlib/hamcrest-core-1.3.jar:
......

BUILD SUCCESSFUL
Total time: 0 seconds 

参考

  1. 蚂蚁路径转换任务

ant (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190115040926/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

ant-Spring MVC 和 WAR 文件示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-spring-mvc-and-war-file-example/

在本教程中,我们将向您展示如何使用 Ant 构建脚本来管理 Spring MVC web 应用程序项目,创建 WAR 文件并部署到 Tomcat。

使用的技术:

  1. Eclipse 4.2
  2. JDK 1.7
  3. Ant 1.9.4
  4. 蚂蚁常春藤 2.4
  5. 回溯 1.1.2
  6. jstl 1.2
  7. 弹簧 4.1.3 .释放
  8. Tomcat 7

1.项目目录

审查最终项目结构:

Ant-SpringMVC-Project

  1. 资源——放置 Java 源代码所需的 xml 和属性文件。比如 log4j.properties,logback.xml,db.properties 等等。
  2. src–放 Java 源代码。
  3. 目标–最终的 WAR 文件将存储在这里。
  4. 战争——与网络相关的东西。
  5. WAR/WEB-INF–WAR 文件的标准 we b-INF 目录结构。
  6. war/resources–用于 css 和 js 文件

2.项目相关性

我们使用 Ivy 下载项目依赖关系:

ivy.xml

 <ivy-module version="2.0">
	<info organisation="org.apache" module="WebProject" />

	<!-- Classpath management, thanks Maven -->
	<configurations>
        <conf name="compile" description="compile dependencies"/>
        <conf name="runtime" description="runtime dependencies" extends="compile"/>
        <conf name="test"    description="test dependencies" extends="runtime"/>
    </configurations>

	<dependencies>
		<dependency org="org.slf4j" name="slf4j-api" rev="1.7.6" conf="compile->default"/>
		<dependency org="jstl" name="jstl" rev="1.2" conf="compile->default"/>
		<dependency org="ch.qos.logback" name="logback-classic" rev="1.1.2" conf="compile->default"/>
		<dependency org="org.springframework" name="spring-core" rev="4.1.3.RELEASE" conf="compile->default"/>
		<dependency org="org.springframework" name="spring-beans" rev="4.1.3.RELEASE" conf="compile->default"/>
		<dependency org="org.springframework" name="spring-context" rev="4.1.3.RELEASE" conf="compile->default"/>
		<dependency org="org.springframework" name="spring-web" rev="4.1.3.RELEASE" conf="compile->default"/>
		<dependency org="org.springframework" name="spring-webmvc" rev="4.1.3.RELEASE" conf="compile->default"/>
	</dependencies>
</ivy-module> 

3.Ant 构建脚本

Ant 脚本来管理这个 Spring MVC 项目,不言自明。

build.xml

 <project xmlns:ivy="antlib:org.apache.ivy.ant" name="HelloProject" default="main" basedir=".">
	<description>
		Create a Spring MVC (WAR) with Ant build script
	</description>

	<!-- Project Structure -->
	<property name="jdk.version" value="1.7" />
	<property name="projectName" value="WebProject" />
	<property name="src.dir" location="src" />
	<property name="resources.dir" location="resources" />
	<property name="web.dir" value="war" />
	<property name="web.classes.dir" location="${web.dir}/WEB-INF/classes" />
	<property name="target.dir" location="target" />
	<property name="target.temp.dir" location="target/temp" />
	<property name="lib.dir" value="lib" />

	<!-- ivy start -->
	<target name="resolve" description="retrieve dependencies with ivy">
		<echo message="Getting dependencies..." />
		<ivy:retrieve />

		<ivy:cachepath pathid="compile.path" conf="compile" />
		<ivy:cachepath pathid="runtime.path" conf="runtime" />
		<ivy:cachepath pathid="test.path" conf="test" />

	</target>

	<!-- install ivy if you don't have ivyide-->
	<target name="ivy" description="Install ivy">
		<mkdir dir="${user.home}/.ant/lib" />
		<get dest="${user.home}/.ant/lib/ivy.jar" 
		src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0-rc1/ivy-2.4.0-rc1.jar" />
	</target>
	<!-- ivy end -->

	<!-- Compile Java source from ${src.dir} and output it to ${web.classes.dir} -->
	<target name="compile" depends="init, resolve" description="compile source code">
		<mkdir dir="${web.classes.dir}" />
		<javac destdir="${web.classes.dir}" source="${jdk.version}" target="${jdk.version}" 
			debug="true" includeantruntime="false" classpathref="compile.path">
			<src path="${src.dir}" />
		</javac>
	</target>

	<!-- Copy *.xml or *.properties from ${resources.dir} to ${web.classes.dir} -->
	<target name="copy-resources" 
                description="copy Java resources like xml and properties files">
		<copy todir="${web.classes.dir}">
			<fileset dir="${resources.dir}">
				<include name="**/*.xml" />
				<include name="**/*.properties" />
			</fileset>
		</copy>
	</target>

	<!-- Create the final WAR file for deployment -->
	<target name="package" depends="clean, compile, copy-resources" 
                description="create a war file">

		<!-- ivy get dependencies and put it in ${lib.dir} -->
		<ivy:retrieve pattern="${lib.dir}/[artifact]-[revision].[ext]" conf="runtime" />

		<war destfile="${target.dir}/helloproject.war" webxml="${web.dir}/WEB-INF/web.xml">

			<webinf dir="${web.dir}/WEB-INF" />
			<lib dir="${lib.dir}" />
			<zipfileset dir="${web.dir}/resources" prefix="resources" />
		</war>
	</target>

	<!-- Create folders -->
	<target name="init">
		<mkdir dir="${src.dir}" />
		<mkdir dir="${target.dir}" />
		<mkdir dir="${web.classes.dir}" />
	</target>

	<!-- Delete folders -->
	<target name="clean" description="clean up">
		<delete dir="${web.classes.dir}" />
		<delete dir="${target.dir}" />
	</target>

	<target name="main" depends="package" />

</project> 

4.Spring MVC、JSP 和 XML 文件

如果您感兴趣,这里有完整的 Java、XML 和 JSP 文件。

4.1 Spring MVC 控制器类。

WelcomeController.java

 package com.mkyong.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class WelcomeController {

	private static final String VIEW_INDEX = "index";
	private final static Logger logger = LoggerFactory.getLogger(WelcomeController.class);

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String welcome(ModelMap model) {

		model.addAttribute("message", "");
		logger.debug("[welcome]");

		return VIEW_INDEX;

	}

	@RequestMapping(value = "/{name}", method = RequestMethod.GET)
	public String welcomeName(@PathVariable String name, ModelMap model) {

		model.addAttribute("message", "Welcome " + name);
		logger.debug("[welcomeName] name : {}", name);
		return VIEW_INDEX;

	}

} 

4.2 简单的日志返回配置文件,用于日志记录。

logback.xml

 <?xml version="1.0" encoding="UTF-8"?>
<configuration>

	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
	  <layout class="ch.qos.logback.classic.PatternLayout">

		<Pattern>
			ANT + LogBack : %-5level %logger{36} - %msg%n
		</Pattern>

	  </layout>
	</appender>

	<root level="debug">
	  <appender-ref ref="STDOUT" />
	</root>

</configuration> 

4.3 JSP 和 CSS 文件。

war/WEB-INF/pages/index.jsp

 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:url var="resources" value="/resources/theme1" scope="request" />

<html>
<head>
<link href="${resources}/css/core.css" rel="stylesheet">
</head>
<body>
<h1>Ant + Spring MVC Web Project Example</h1>

<p>Message : ${message}</p>	
</body>
</html> 

war/resources/theme1/css/core.css

 h1 {
	font-size: 50px;
}

p {
	font-size: 20px;
	border: 5px solid red;
	padding:10px;
} 

4.4 弹簧配置。

mvc-dispatcher-servlet.xml

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc 
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<context:component-scan base-package="com.mkyong.controller" />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

	<!-- for web resources like images, css and js files -->
	<mvc:resources mapping="/resources/**" location="/resources/" />

	<mvc:annotation-driven />

</beans> 

4.5 一个标准的 web.xml,与 Spring 容器集成。

web.xml

 <web-app  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>Ant + Spring MVC Web Application</display-name>

	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app> 

5.运行和测试

5.1 默认情况下,它会运行package任务。

 $ pwd
/Users/mkyong/Documents/workspace/AntSpringMVC

$ ant

Buildfile: /Users/mkyong/Documents/workspace/AntSpringMVC/build.xml

clean:
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntSpringMVC/war/WEB-INF/classes
   [delete] Deleting directory /Users/mkyong/Documents/workspace/AntSpringMVC/target

init:
    [mkdir] Created dir: /Users/mkyong/Documents/workspace/AntSpringMVC/target
    [mkdir] Created dir: /Users/mkyong/Documents/workspace/AntSpringMVC/war/WEB-INF/classes

resolve:
     [echo] Getting dependencies...
[ivy:retrieve] :: Apache Ivy 2.4.0-rc1 - 20140315220245 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/Users/mkyong/.ant/lib/ivy.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#WebProject;working@mkyong-mac
[ivy:retrieve] 	confs: [compile, runtime, test]
[ivy:retrieve] 	found org.slf4j#slf4j-api;1.7.6 in public
[ivy:retrieve] 	found jstl#jstl;1.2 in public
[ivy:retrieve] 	found ch.qos.logback#logback-classic;1.1.2 in public
[ivy:retrieve] 	found ch.qos.logback#logback-core;1.1.2 in public
[ivy:retrieve] 	found org.springframework#spring-core;4.1.3.RELEASE in public
[ivy:retrieve] 	found commons-logging#commons-logging;1.2 in public
[ivy:retrieve] 	found org.springframework#spring-beans;4.1.3.RELEASE in public
[ivy:retrieve] 	found org.springframework#spring-context;4.1.3.RELEASE in public
[ivy:retrieve] 	found org.springframework#spring-aop;4.1.3.RELEASE in public
[ivy:retrieve] 	found aopalliance#aopalliance;1.0 in public
[ivy:retrieve] 	found org.springframework#spring-expression;4.1.3.RELEASE in public
[ivy:retrieve] 	found org.springframework#spring-web;4.1.3.RELEASE in public
[ivy:retrieve] 	found org.springframework#spring-webmvc;4.1.3.RELEASE in public
[ivy:retrieve] :: resolution report :: resolve 974ms :: artifacts dl 19ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      compile     |   13  |   0   |   0   |   0   ||   13  |   0   |
	|      runtime     |   13  |   0   |   0   |   0   ||   13  |   0   |
	|       test       |   13  |   0   |   0   |   0   ||   13  |   0   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#WebProject
[ivy:retrieve] 	confs: [compile, runtime, test]
[ivy:retrieve] 	2 artifacts copied, 11 already retrieved (682kB/31ms)

compile:
    [javac] Compiling 1 source file to /Users/mkyong/Documents/workspace/AntSpringMVC/war/WEB-INF/classes

copy-resources:
     [copy] Copying 1 file to /Users/mkyong/Documents/workspace/AntSpringMVC/war/WEB-INF/classes

package:
[ivy:retrieve] :: retrieving :: org.apache#WebProject
[ivy:retrieve] 	confs: [runtime]
[ivy:retrieve] 	0 artifacts copied, 13 already retrieved (0kB/11ms)
      [war] Building war: /Users/mkyong/Documents/workspace/AntSpringMVC/target/helloproject.war

main:

BUILD SUCCESSFUL
Total time: 3 seconds 

根据您开发环境,上述结果可能会有所不同。如果构建成功,最终的 WAR 文件将被创建在target文件夹中。

5.2 查看生成的 WAR 文件的内容—helloproject.war

 mkyong-mac:AntSpringMVC mkyong$ tar -tvf target/helloproject.war 
drwxrwxrwx  0 0      0           0 Dec 26 16:55 META-INF/
-rwxrwxrwx  0 0      0         103 Dec 26 16:55 META-INF/MANIFEST.MF
drwxrwxrwx  0 0      0           0 Dec 26 16:55 WEB-INF/
-rwxrwxrwx  0 0      0         897 Dec 24 15:05 WEB-INF/web.xml
drwxrwxrwx  0 0      0           0 Dec 26 16:55 WEB-INF/classes/
drwxrwxrwx  0 0      0           0 Dec 26 16:55 WEB-INF/classes/com/
drwxrwxrwx  0 0      0           0 Dec 26 16:55 WEB-INF/classes/com/mkyong/
drwxrwxrwx  0 0      0           0 Dec 26 16:55 WEB-INF/classes/com/mkyong/controller/
drwxrwxrwx  0 0      0           0 Dec 24 17:05 WEB-INF/lib/
drwxrwxrwx  0 0      0           0 Dec 24 15:04 WEB-INF/pages/
-rwxrwxrwx  0 0      0        1903 Dec 26 16:55 WEB-INF/classes/com/mkyong/controller/WelcomeController.class
-rwxrwxrwx  0 0      0         372 Dec 26 16:55 WEB-INF/classes/logback.xml
-rwxrwxrwx  0 0      0        1030 Dec 25 13:41 WEB-INF/mvc-dispatcher-servlet.xml
-rwxrwxrwx  0 0      0         311 Dec 25 13:44 WEB-INF/pages/index.jsp
-rwxrwxrwx  0 0      0        4467 Aug  1  2005 WEB-INF/lib/aopalliance-1.0.jar
-rwxrwxrwx  0 0      0       61829 Jul  6 02:12 WEB-INF/lib/commons-logging-1.2.jar
-rwxrwxrwx  0 0      0      414240 Jul 22  2006 WEB-INF/lib/jstl-1.2.jar
-rwxrwxrwx  0 0      0      270750 Apr  3  2014 WEB-INF/lib/logback-classic-1.1.2.jar
-rwxrwxrwx  0 0      0      427729 Apr  3  2014 WEB-INF/lib/logback-core-1.1.2.jar
-rwxrwxrwx  0 0      0       28688 Feb  6  2014 WEB-INF/lib/slf4j-api-1.7.6.jar
-rwxrwxrwx  0 0      0      359018 Dec  9 18:48 WEB-INF/lib/spring-aop-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0      707820 Dec  9 18:48 WEB-INF/lib/spring-beans-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0     1026840 Dec  9 18:48 WEB-INF/lib/spring-context-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0     1006709 Dec  9 18:48 WEB-INF/lib/spring-core-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0      259164 Dec  9 18:48 WEB-INF/lib/spring-expression-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0      713531 Dec  9 18:48 WEB-INF/lib/spring-web-4.1.3.RELEASE.jar
-rwxrwxrwx  0 0      0      781676 Dec  9 18:48 WEB-INF/lib/spring-webmvc-4.1.3.RELEASE.jar
drwxrwxrwx  0 0      0           0 Dec 26 16:48 resources/
drwxrwxrwx  0 0      0           0 Dec 25 13:30 resources/theme1/
drwxrwxrwx  0 0      0           0 Dec 25 13:27 resources/theme1/css/
-rwxrwxrwx  0 0      0          88 Dec 25 13:45 resources/theme1/css/core.css 

所有文件都是放置属性,要部署它只需复制helloproject.war并将其放入$Tomcat/webapps文件夹。

5.3 http://localhost:8080/hello project/

ant-spring-mvc-example1

5.4 http://localhost:8080/hello project/mkyong

ant-spring-mvc-example2Note
Follow up : how to debug this ant-ivy project in Eclipse IDE.

下载源代码

Download It – Ant-SpringMVC-Example.zip (26 KB)

参考

  1. 蚂蚁常春藤检索模式
  2. 蚂蚁类型 zipfileset
  3. 蚂蚁大战任务
  4. 蚂蚁复制任务
  5. Stackoverflow : Ivy 类路径管理
  6. W3schools CSS Border
  7. Ant–如何使用外部库创建 Jar 文件
  8. 伊夫德 WTP 集成
  9. Maven:如何创建 web 项目
  10. Spring IO : Spring MVC 步步为营

构建 Java 项目的 Ant 模板文件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/ant/ant-template-file-to-build-a-java-project/

这里有一个 Apache Ant 模板文件,最适合用来从头开始一个项目。

文件:build.xml

 <project name="ProjectName" default="dist" basedir=".">
    <description>
        Project Description
    </description>

  <!-- set global properties for this build -->
  <property name="projectName" value="ProjectName"/>
  <property name="src" location="src"/>
  <property name="build" location="build"/>
  <property name="dist"  location="dist"/>
  <property name="webcontent"  location="WebContent"/>

  <target name="init">
    	<!-- Create the time stamp -->
   	 <tstamp/>
    	<!-- Create the build directory structure used by compile -->
    	<mkdir dir="${build}"/>
  </target>

  <target name="compile" depends="init"
  	description="compile the source " >
    	<!-- Compile the java code from ${src} into ${build} -->
   	<javac srcdir="${src}" destdir="${build}"/>
  </target>

  <target name="dist" depends="compile"
  	description="generate the distribution" >

  	<!-- Create the distribution directory -->
    	<mkdir dir="${dist}/lib"/>

    	<!-- Put everything in ${build} into the {$projectName}-${DSTAMP}.jar file -->
    	<jar jarfile="${dist}/lib/${projectName}-${DSTAMP}.jar" basedir="${build}"/>
  </target>

  <target name="war" depends="compile"
  	description="generate the distribution war" >

	<!-- Create the war distribution directory -->
  	<mkdir dir="${dist}/war"/>

  	<!-- Follow standard WAR structure -->
  	<copydir dest="${dist}/war/build/WEB-INF/" src="${webcontent}/WEB-INF/" />
  	<copydir dest="${dist}/war/build/WEB-INF/classes/" src="${build}" />

	<jar jarfile="${dist}/war/${projectName}-${DSTAMP}.war" basedir="${dist}/war/build/"/>
  </target>

  <target name="clean"
    	description="clean up" >

    	<!-- Delete the ${build} and ${dist} directory trees -->
    	<delete dir="${build}"/>
    	<delete dir="${dist}"/>
  </target>
</project> 

Apache Ant 教程

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/apache-ant-tutorial/

ant-logo

Apache Ant ,是一个经典的 Java 项目构建工具。

P.S Apache Ant 版本:1.9.4

1.教程

常见问题解答

ant tutorials (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214234113/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

将 Android 源代码附加到 Eclipse IDE

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/android/attach-android-source-code-to-eclipse-ide/

默认情况下, Android SDKEclipse ADT 插件不捆绑任何 Android 的源代码进行调试。在 Eclipse IDE 中,进入任何 Android 类都将提示没有附加源代码,请参见下面的屏幕:

android source code not found in Eclipse

解决办法

根据这个官方的 Android 源代码文章,震惊的是我们需要使用repo下载然后构建完整的源代码来获得android.jar的源代码。

如果你认为上面的工作太多,或者,你可以安装名为“ Android Source 的 Eclipse 插件来获得“android.jar的源代码。阅读这篇文章“【Android 的附加 Eclipse 插件”。

在安装了" Android source "插件后,假设现有项目以及新创建的针对 Android 的项目将自动附加源代码 jar。然而,我现有的 Android 项目仍然没有附加到正确的源,我必须手动附加它。

找到" Android Source "插件文件夹,它应该在以下目录中:

 ECLIPSE_PATH\plugins\com.android.ide.eclipse.source_MAY_BE_VARY 

文件夹:

android source folders

  • 14–安卓 4.0.1
  • 10–安卓 2.3.4
  • 9–安卓 2.3
  • 8–安卓 2.2
  • 7–安卓 2.1
  • 6–安卓 2.0.1
  • 4–安卓 1.6
  • 3–安卓 1.5

每个文件夹包含一个“ sources.zip ”,它针对特定的 Android 版本。比如你开发的是 Android 2.3 ,那么从文件夹“ 10 ”中获取“ sources.zip ,手动将其附加到 Eclipse IDE 中。

再次踏入 Android 类,源代码显示。

attach android source code to eclipse ide

参考

  1. 【Android 的附加 Eclipse 插件
  2. Android 开源项目

Tags : android eclipse source code

相关文章

无法更改 HTTP accept 标头-使用不同的区域设置解析策略

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/cannot-change-http-accept-header-use-a-different-locale-resolution-strategy/

问题

在 Spring MVC 应用程序中,当用"org . Spring framework . web . servlet . i18n . localechangeinterceptor"更改区域设置时,遇到以下错误

 java.lang.UnsupportedOperationException: 
     Cannot change HTTP accept header - use a different locale resolution strategy
     ...AcceptHeaderLocaleResolver.setLocale(AcceptHeaderLocaleResolver.java:45) 

解决办法

在 Spring MVC 应用程序中,如果不配置 Spring 的 LocaleResolver,它将使用默认的AcceptHeaderLocaleResolver,这不允许更改区域设置。要解决这个问题,请尝试在 Spring bean 配置文件中声明一个session locale resolverbean,它应该适合大多数情况。

 <beans ...

	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
		<property name="defaultLocale" value="en" />
	</bean>

	<bean id="localeChangeInterceptor"
		class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName" value="language" />
	</bean>

	<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
		<property name="interceptors">
			<list>
				<ref bean="localeChangeInterceptor" />
			</list>
		</property>
	</bean>

</beans> 

参考

  1. locale solver 文档

spring mvc

在 org . Apache . struts . action . message 项下找不到消息资源

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts/cannot-find-message-resources-under-key-org-apache-struts-action-message/

问题

Struts 框架中一个常见的资源包错误,它通常是由系统找不到相应的消息资源引起的。

 javax.servlet.jsp.JspException: Cannot find message resources under key org.apache.struts.action.MESSAGE
	org.apache.struts.taglib.TagUtils.retrieveMessageResources(TagUtils.java:1112)
	org.apache.struts.taglib.TagUtils.present(TagUtils.java:1055)
	org.apache.struts.taglib.html.ErrorsTag.doStartTag(ErrorsTag.java:200)
	org.apache.jsp.pages.login_jsp._jspx_meth_html_005ferrors_005f0(login_jsp.java:160)
	org.apache.jsp.pages.login_jsp._jspx_meth_html_005fform_005f0(login_jsp.java:111)
	org.apache.jsp.pages.login_jsp._jspService(login_jsp.java:77)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:831)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:831)
	org.apache.struts.chain.commands.servlet.PerformForward.handleAsForward(PerformForward.java:113)
	org.apache.struts.chain.commands.servlet.PerformForward.perform(PerformForward.java:96)
	org.apache.struts.chain.commands.AbstractPerformForward.execute(AbstractPerformForward.java:54)
	org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
	org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
	org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)
	org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
	org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
	org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
	org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:718)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:831) 

解决办法

只需包含相应的消息资源。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC 
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" 
"http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">

<struts-config>

	<message-resources
		parameter="com.mkyong.common.properties.Common" />

</struts-config> 

struts (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190209024201/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

找不到基本名称 xxx,区域设置 en_US 的包

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/cant-find-bundle-for-base-name-xxx-locale-en_us/

问题

在 JSF web 应用中,在应用层加载一个消息包,如下:
faces-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<faces-config

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
     <application>
	<message-bundle>
		com.mkyong.payment_error
	</message-bundle>
     </application>
</faces-config> 

页面渲染时,遇到“找不到 base name com . mkyong . payment _ error,locale en_US 的 bundle”?

解决办法

显然,包或属性文件(com . mkyong . payment _ error . properties)丢失了,请确保名称匹配并正确放置在资源文件夹中。

For Eclipse User
This problem is usually happened in the Eclipse IDE environment, where it doesn’t copy the “.properties” file extension by default. So, just make sure the properties file is existed in the run time “classes” folder and can be located by your web application.jsf2 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190224212715/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

cascade–JPA & Hibernate 注释常见错误

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/

很多时候,开发人员混合使用 JPA 和 Hibernate 注释,这将导致一个非常常见的错误——JPA 级联类型注释在 Hibernate 中不起作用?

在代码审查阶段,我发现许多 Java 开发人员没有意识到这个错误,导致程序无法对相关实体执行级联操作。我将以这个一对多 hibernate 示例为例进行演示。

错误

在一对多示例中,许多开发人员声明 JPA 级联选项如下:

 ...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    ...
    private Set<StockDailyRecord> stockDailyRecords = 
                                              new HashSet<StockDailyRecord>(0);

    @OneToMany(fetch = FetchType.LAZY, 
       cascade = {CascadeType.PERSIST,CascadeType.MERGE }, 
       mappedBy = "stock")
    public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
    }

    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
    }
    ... 

用 Hibernate 会话保存它。

 stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);

        session.save(stock);
        session.getTransaction().commit(); 

这段代码试图做的是,当您保存一个“股票”时,它也会保存相关的 stockDailyRecords。一切看起来都很好,但是这不起作用,级联选项将不会执行和保存 stockDailyRecords。你能发现这个错误吗?

说明

在代码中, @OneToMany 来自 JPA,它期望一个 JPA 级联-javax . persistence . cascadetype。然而,当你用 Hibernate 会话保存它时,org . Hibernate . engine . cascade会做如下检查…

 if ( style.doCascade( action ) ) {
		cascadeProperty(
	          persister.getPropertyValue( parent, i, entityMode ),
		  types[i],
    	          style,
	          anything,
	          false
		);
	} 

Hibernate save 进程会导致一个 ACTION_SAVE_UPDATE 动作,但是 JPA 会传递一个 ACTION_PERSISTACTION_MERGE ,它们不匹配,导致级联执行失败。

@见源代码

  • org . hibernate . engine . cascade
  • org . hibernate . engine . cascade style
  • org . hibernate . engine . cascading action

解决办法

删除 JPA cascade-javax . persistence . cascade type,替换为 Hibernate cascade-org . Hibernate . annotations . cascade,替换为 CascadeType。保存 _ 更新

 ...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    ...
    private Set<StockDailyRecord> stockDailyRecords = 
                                              new HashSet<StockDailyRecord>(0);

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    @Cascade({CascadeType.SAVE_UPDATE})
    public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
    }

    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
    }
    ... 

现在,它如你所料地工作了。

结论

JPA 和 Hibernate cascade 注释之间似乎存在不兼容的问题,如果 Hibernate 是 JPA 的实现,是什么导致了两者之间的误解?

处理@Configuration 类需要 CGLIB

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/cglib-is-required-to-process-configuration-classes/

问题

使用 Spring3 @Configuration创建如下所示的应用程序配置文件:

 import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

	@Bean
   //...

} 

但是,当运行它时,它会显示以下错误消息:

 org.springframework.context.support.AbstractApplicationContext prepareRefresh
//...
Exception in thread "main" java.lang.IllegalStateException: 
CGLIB is required to process @Configuration classes. 
Either add CGLIB to the classpath or remove the following 
@Configuration bean definitions: [appConfig]
//...
at com.mkyong.core.App.main(App.java:12) 

解决办法

要在 Spring 3 中使用@Configuration,需要手动包含 CGLIB 库,只需在 Maven pom.xml文件中声明即可。

 <dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2.2</version>
	</dependency> 

Tags : cglib spring3

notfounindexception:com . opensymphony . xwork 2 . util . finder . test

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/classnotfoundexception-com-opensymphony-xwork2-util-finder-test/

问题

一个启用了 Struts 2 注释的项目,在服务器启动期间点击了以下错误消息。

 Caused by: java.lang.NoClassDefFoundError: com/opensymphony/xwork2/util/finder/Test
  at java.lang.Class.getDeclaredConstructors0(Native Method)
  at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
  at java.lang.Class.getDeclaredConstructors(Unknown Source)
  ... 24 more
Caused by: java.lang.ClassNotFoundException: com.opensymphony.xwork2.util.finder.Test
  at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
  at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1361)
  ... 28 more 

解决办法

缺少" xwork.jar "库,这是 Struts 2 开发中所需要的。从 Maven 中央存储库下载它。

 <dependency>
           <groupId>com.opensymphony</groupId>
           <artifactId>xwork</artifactId>
           <version>2.1.3</version>
    </dependency> 

struts2 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225092427/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

ClassNotFoundException:com . sun . syndication . feed . wire feed

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/classnotfoundexception-com-sun-syndication-feed-wirefeed/

问题

用 Spring MVC 开发 RSS,扩展了“AbstractRssFeedView”,在应用程序启动时出现以下错误信息。

 Caused by: java.lang.NoClassDefFoundError: com/sun/syndication/feed/WireFeed
	at java.lang.Class.getDeclaredConstructors0(Native Method)
	at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
	at java.lang.Class.getDeclaredConstructors(Class.java:1836)
	//...
Caused by: java.lang.ClassNotFoundException: com.sun.syndication.feed.WireFeed
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1361)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 41 more 

解决办法

Spring MVC 使用"罗马"来生成 RSS 提要。对于 Maven,在pom.xml文件中包含下面的依赖关系。

 <dependency>
		<groupId>net.java.dev.rome</groupId>
		<artifactId>rome</artifactId>
		<version>1.0.0</version>
	</dependency> 

spring mvc (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225093251/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

ClassNotFoundException:com . thoughtworks . xstream . io . hierarchical streamreader

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/classnotfoundexception-com-thoughtworks-xstream-io-hierarchicalstreamreader/

问题

Spring MVC 中的 XML 开发,通过 oxm,命中“HierarchicalStreamReader”类未发现异常?

 Caused by: java.lang.ClassNotFoundException: com.thoughtworks.xstream.io.HierarchicalStreamReader
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1361)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 49 more 

解决办法

类“HierarchicalStreamReader”属于“ xstream.jar ”。如果您使用的是 Maven,那么在您的pom.xml文件中声明以下依赖关系。

 <dependency>
		<groupId>com.thoughtworks.xstream</groupId>
		<artifactId>xstream</artifactId>
		<version>1.3.1</version>
	</dependency> 

Note
For Ant user, just download the “xstream.jar” from http://xstream.codehaus.org/ directly.spring mvc (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190306164910/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

ClassNotFoundException:DefaultSavedRequest

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-security/classnotfoundexception-defaultsavedrequest/

问题

与 Spring Security 合作,哪个 jar 包含DefaultSavedRequest

 SEVERE: Exception loading sessions from persistent storage
java.lang.ClassNotFoundException: 
        org.springframework.security.web.savedrequest.DefaultSavedRequest
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252) 

解决办法

DefaultSavedRequestspring-security-web.jar 里面。访问这个 Spring Security hello world 示例获得依赖库列表。

 <!-- Spring Security & dependencies -->
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-core</artifactId>
		<version>3.0.5.RELEASE</version>
	</dependency>

	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-web</artifactId>
		<version>3.0.5.RELEASE</version>
	</dependency>

	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
		<version>3.0.5.RELEASE</version>
	</dependency> 

spring security (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190306155926/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

ClassNotFoundException:org . Apache . XML . serialize . XML serializer

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/classnotfoundexception-org-apache-xml-serialize-xmlserializer/

问题

使用 Spring OXM + Castor 绑定,添加了 Castor 库,但是仍然会出现下面的错误消息?

 Exception in thread "main" java.lang.RuntimeException: 
	Could not instantiate serializer org.apache.xml.serialize.XMLSerializer: 
	java.lang.ClassNotFoundException: org.apache.xml.serialize.XMLSerializer
	at org.exolab.castor.xml.XercesSerializer.<init>(XercesSerializer.java:50)
	//... 

Maven 中的 Castor 依赖。

 <dependency>
		<groupId>org.codehaus.castor</groupId>
		<artifactId>castor</artifactId>
		<version>1.2</version>
	</dependency>

解决办法

如果没有弄错的话, Castor 需要 Xerces 来工作,所以,您还需要添加 Xerces 依赖项。

 <dependencies>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>3.0.5.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.codehaus.castor</groupId>
			<artifactId>castor</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>xerces</groupId>
			<artifactId>xercesImpl</artifactId>
			<version>2.8.1</version>
		</dependency>

	</dependencies> 

Tags : oxm spring3

ClassNotFoundException:org . exolab . castor . XML . XML exception

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/classnotfoundexception-org-exolab-castor-xml-xmlexception/

问题

在 Spring OXM(对象 XML 映射)中,当将一个对象转换为 XML 文件时,会遇到以下错误消息:

 Caused by: java.lang.ClassNotFoundException: org.exolab.castor.xml.XMLException
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 29 more 

Spring oxm 中是否包含 castor 数据绑定框架

解决办法

castor 是 spring-oxm.jar 中的一个可选依赖项,要在 Spring OXM 中使用 castor 来编组和解组 XML,将这个 castor 依赖项添加到您的 Maven pom.xml文件中。

 <dependencies>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>3.0.5.RELEASE</version>
		</dependency>

		<!-- Uses Castor for XML -->
		<dependency>
			<groupId>org.codehaus.castor</groupId>
			<artifactId>castor</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- Castor need this -->
		<dependency>
			<groupId>xerces</groupId>
			<artifactId>xercesImpl</artifactId>
			<version>2.8.1</version>
		</dependency>

	</dependencies> 

oxm spring3 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190121170502/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Struts 2 组合框示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/struts-2-scombobox-combo-box-example/

Download It – Struts-ComboBox-Example.zip

在 Struts 2 中, < s:combobox > 标签基本上是一个与单行文本框组合在一起的下拉列表,允许用户直接在文本框中键入值或从下拉列表中选择值,所选值将自动填充到文本框中。

In case you are confuse between drop down list and combo box list, read the combo box definition from Wiki.

 <s:combobox label="What's your favor fruit" 
		headerKey="-1" headerValue="--- Select ---"
		list="fruits" 
		name="yourFruits" /> 

产生以下 HTML 代码…

 <td class="tdLabel">
   <label for="resultAction_yourFruits" class="label">
       What's your favor fruit:
   </label>
</td> 
<td> 
<script type="text/javascript"> 
function autoPopulate_resultAction_yourFruits(targetElement) {
	if (targetElement.options[targetElement.selectedIndex].value == '-1') {
		return;
	}
	targetElement.form.elements['yourFruits'].value=
              targetElement.options[targetElement.selectedIndex].value;
}
</script> 
<input type="text" name="yourFruits" value="" id="resultAction_yourFruits"/>
<br /> 
<select onChange="autoPopulate_resultAction_yourFruits(this);"> 
    <option value="-1">--- Select ---</option> 
    <option value="Apple">Apple</option> 
    <option value="Banana">Banana</option> 
    <option value="Orange">Orange</option> 
    <option value="Watermelon">Watermelon</option> 
</select> 
</td> 

< s:combobox > 标签会生成一个输入文本框,下拉列表带有一个“ onChange() ”行为来调用生成的 JavaScript 函数,自动将下拉列表中选择的值填充到生成的文本框中。

To create a drop down list , you should use <s:select> tag instead.

struts 2<s:combobox>示例

一个完整的 Struts 2 示例,通过 < s:combobox > 展示组合框的使用

1.行动

Action 类来生成并保存选定的组合框选项。
ComboBoxAction.java

 package com.mkyong.common.action;

import java.util.ArrayList;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

public class ComboBoxAction extends ActionSupport{

	private List<String> fruits;

	private String yourFruits;
	private String yourMonth;

	public String getYourMonth() {
		return yourMonth;
	}

	public void setYourMonth(String yourMonth) {
		this.yourMonth = yourMonth;
	}

	public List<String> getFruits() {
		return fruits;
	}

	public void setFruits(List<String> fruits) {
		this.fruits = fruits;
	}

	public String getYourFruits() {
		return yourFruits;
	}

	public void setYourFruits(String yourFruits) {
		this.yourFruits = yourFruits;
	}

	public ComboBoxAction(){

		fruits = new ArrayList<String>();
		fruits.add("Apple");
		fruits.add("Banana");
		fruits.add("Orange");
		fruits.add("Watermelon");
	}

	public String execute() {
		return SUCCESS;
	}

	public String display() {
		return NONE;
	}

} 

2.结果页面

通过“ < s:combobox > ”标签呈现组合框,通过 Java list 和 OGNL list 填充选择选项

combobox.jsp

 <%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
</head>

<body>
<h1>Struts 2 &lt;s:combobox&gt; example</h1>

<s:form action="resultAction" namespace="/">

<h2>
	<s:combobox label="What's your favor fruit" 
		headerKey="-1" headerValue="--- Select ---"
		list="fruits" 
		name="yourFruits" />
</h2>

<h2>
	<s:combobox label="Select a month" 
		headerKey="-1" headerValue="--- Select ---"
		list="#{'1':'Jan', '2':'Feb', '3':'Mar', '4':'Apr'}" 
		name="yourMonth" />
</h2> 

<s:submit value="submit" name="submit" />

</s:form>

</body>
</html> 

result.jsp

 <%@ taglib prefix="s" uri="/struts-tags" %>
<html>

<body>
<h1>Struts 2 &lt;s:combobox&gt; example</h1>

<h2>
  Favor fruit : <s:property value="yourFruits"/>
</h2> 

<h2>
  Selected month : <s:property value="yourMonth"/>
</h2> 

</body>
</html> 

3.struts.xml

链接在一起~

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

 <constant name="struts.devMode" value="true" />

<package name="default" namespace="/" extends="struts-default">

   <action name="comboBoxAction" 
         class="com.mkyong.common.action.ComboBoxAction" method="display">
	<result name="none">pages/combobox.jsp</result>
   </action>

   <action name="resultAction" class="com.mkyong.common.action.ComboBoxAction">
	<result name="success">pages/result.jsp</result>
   </action>

</package>

</struts> 

5.演示

http://localhost:8080/struts 2 example/comboboxation . action

Struts 2 combo box example

http://localhost:8080/struts 2 example/result action . action

Struts 2 combo box example

参考

  1. Struts 2 组合框文档
  2. 维基组合框定义

Tags : dropdown struts2

JSF 2.0 中的复合组件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/composite-components-in-jsf-2-0/

从 JSF 2.0 开始,创建一个可重用的组件变得非常容易,被称为复合组件。在本教程中,我们将向您展示如何创建一个简单的复合组件(存储为“ register.xhtml ”),这是一个用户注册表单,包括姓名和电子邮件文本字段(h:inputText)和一个提交按钮(h:commandButton)。此外,我们还向您展示如何使用它。

创建一个复合组件

下面是创建复合组件的步骤:

freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });

1.复合名称空间

创建一个。xhtml 文件,并声明了复合名称空间。

 <html    
      //...
      xmlns:composite="http://java.sun.com/jsf/composite">
</html> 

2.接口和实施

使用复合标签composite:interfacecomposite:attributecomposite:implementation,定义复合组件的内容。举个例子,

 <html    
      //...
      xmlns:composite="http://java.sun.com/jsf/composite">

	  <composite:interface>
			<composite:attribute name="anything" />
	  </composite:interface>

	  <composite:implementation>
			#{cc.attrs.anything}
	  </composite:implementation>
</html> 

composite:interface标签用于声明可配置的值,这些值向使用它的开发人员公开。而composite:implementation标签声明了所有的 XHTML 标记,也就是复合组件的内容,在composite:implementation标签里面,你可以用表达式#{cc.attrs.attributeName}访问composite:interface属性。

3.资源文件夹

把复合组件(“。xhtml "文件)放到 JSF 的资源文件夹中,见图 1:

图 1:这个例子的目录结构。

jsf2-composite-component-folder

在本例中,您将“ register.xhtml ”复合组件放入名为“mkyong”的文件夹中。

4.完整示例

做完了,让我们来看一个完整的“register.xhtml”的例子。

文件:register.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:composite="http://java.sun.com/jsf/composite"
      >

    <composite:interface>

    	<composite:attribute name="nameLable" />
    	<composite:attribute name="nameValue" />
    	<composite:attribute name="emailLable" />
    	<composite:attribute name="emailValue" />

   	<composite:attribute name="registerButtonText" />
    	<composite:attribute name="registerButtonAction" 
    		method-signature="java.lang.String action()" />

    </composite:interface>

    <composite:implementation>

	<h:form>

		<h:message for="textPanel" style="color:red;" />

		<h:panelGrid columns="2" id="textPanel">

			#{cc.attrs.nameLable} : 
			<h:inputText id="name" value="#{cc.attrs.nameValue}" />

			#{cc.attrs.emailLable} : 
			<h:inputText id="email" value="#{cc.attrs.emailValue}" />

		</h:panelGrid>

		<h:commandButton action="#{cc.attrs.registerButtonAction}" 
			value="#{cc.attrs.registerButtonText}"
		/>

	</h:form>

    </composite:implementation>

</html> 

使用复合组件

您刚刚创建了一个复合组件“register.xhtml ”,现在我们将向您展示如何使用它。

1.复合组件访问路径

参考上面的图 1;“register.xhtml”文件在“mkyong”文件夹下。以下是您访问它的方式:

 <html    
      ///...
      xmlns:mkyong="http://java.sun.com/jsf/composite/mkyong"
      >
	  <mkyong:register />
</html> 

http://java.sun.com/jsf/composite/folder-name-in-resources-folder
The folder name of the composite components is defined the component access path, for example, if you put your “register.xhtml” file under folder named “abc”, then you should access it like this :

 <html    
      ///...
      xmlns:mkyong="http://java.sun.com/jsf/composite/abc"
      >
	  <mkyong:register />
</html> 

2.完整示例

让我们看一个完整的例子来展示“register.xhtml”复合组件的用法。

文件:default.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:mkyong="http://java.sun.com/jsf/composite/mkyong"
      >

    <h:body>

    	<h1>Composite Components in JSF 2.0</h1>

	<mkyong:register 
		nameLable="Name" 
		nameValue="#{user.name}" 
		emailLable="E-mail" 
		emailValue="#{user.email}"

		registerButtonText="Register" 
		registerButtonAction="#{user.registerAction}"
	 />

    </h:body>

</html> 

您可以通过暴露的属性将硬编码值或支持方法或属性传递到复合组件中,当提交表单时,JSF 将自动完成所有支持 bean 绑定。

对那些感兴趣的人来说,这是“用户”管理或支持的 bean。

 package com.mkyong;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="user")
@SessionScoped
public class UserBean{

	public String name;
	public String email;

	//getter and setter methods for name and email

	public String registerAction(){
		return "result";
	}
} 

演示

这是结果。

URL:http://localhost:8080/Java server faces/default . XHTML

jsf2-composite-component-example

下载源代码

Download It – JSF-2-Composite-Components-Example.zip (11KB)

参考

  1. JSF 2 组合:接口 JavaDoc
  2. JSF 新组合:实现 JavaDoc
  3. JSF 2 复合:属性 JavaDoc

Tags : component jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });

JSF 2.0 中的条件导航规则

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/conditional-navigation-rule-in-jsf-2-0/

JSF 2 附带了一个非常灵活的条件导航规则来解决复杂的页面导航流程,参见下面的条件导航规则示例:

1.JSF·佩奇

一个简单的 JSF 页面,有一个按钮从这个页面移动到支付页面。

start.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html">

    <h:body>
    	<h2>This is start.xhtml</h2>
	<h:form>
    	   <h:commandButton action="payment" value="Payment" />
	</h:form>
    </h:body>
</html> 

2.受管 Bean

一个受管 bean,提供示例数据以在导航规则中执行条件检查。

 import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped; 
import java.io.Serializable;

@ManagedBean
@SessionScoped
public class PaymentController implements Serializable {

	private static final long serialVersionUID = 1L;

	public boolean registerCompleted = true;
	public int orderQty = 99;

	//getter and setter methods
} 

3.条件导航规则

通常,您在“faces-config.xml”中声明简单的导航规则,如下所示:

 <navigation-rule>
	<from-view-id>start.xhtml</from-view-id>
	<navigation-case>
		<from-outcome>payment</from-outcome>
		<to-view-id>payment.xhtml</to-view-id>
	</navigation-case>
</navigation-rule> 

在 JSF 新协议中,您可以在进入支付页面之前添加一些条件检查,请参见以下内容:

faces-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<faces-config

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">

	<navigation-rule>
		<from-view-id>start.xhtml</from-view-id>
		<navigation-case>
			<from-outcome>payment</from-outcome>
			<if>#{paymentController.orderQty &lt; 100}</if>
			<to-view-id>ordermore.xhtml</to-view-id>
		</navigation-case>
		<navigation-case>
			<from-outcome>payment</from-outcome>
			<if>#{paymentController.registerCompleted}</if>
			<to-view-id>payment.xhtml</to-view-id>
		</navigation-case>
		<navigation-case>
			<from-outcome>payment</from-outcome>
			<to-view-id>register.xhtml</to-view-id>
		</navigation-case>
	</navigation-rule>

</faces-config> 

这相当于下面的 Java 代码:

 if (from-view-id == "start.xhtml"){

   if(from-outcome == "payment"){

      if(paymentController.orderQty < 100){
	  return "ordermore";
      }else if(paymentController.registerCompleted){
	  return "payment";
      }else{
	  return "register";
      }

   }

} 

代码应该足够简单明了。

Note
In the conditional navigation rule, the sequence of the navigation rule does affect the navigation flow, always put the highest checking priority in the top.

4.测试

用于测试的不同数据集:

例 1

 public class PaymentController implements Serializable {

	public boolean registerCompleted = true;
	public int orderQty = 99;
	... 

当这个按钮被点击时,它达到了"payment controller . order qty<100"标准,并移动到" ordermore.xhtml "页面。

例 2

 public class PaymentController implements Serializable {

	public boolean registerCompleted = true;
	public int orderQty = 200;
	... 

当按钮被点击时,它点击"payment controller . register completed"标准并移动到" payment.xhtml "页面。

例 3

 public class PaymentController implements Serializable {

	public boolean registerCompleted = false;
	public int orderQty = 200;
	... 

当按钮被单击时,它没有通过所有的检查标准,并移动到“register.xhtml”页面。

建议

在 JSF 2.0 中,条件导航规则中没有“ else 标签,希望 JSF 团队能在未来的版本中包含“else”标签。举个例子,

 <navigation-rule>
	<from-view-id>start.xhtml</from-view-id>
	<navigation-case>
		<from-outcome>payment</from-outcome>
		<if>#{paymentController.orderQty &lt; 100}</if>
			<to-view-id>ordermore.xhtml</to-view-id>
		<else if>#{paymentController.registerCompleted}</else if>
			<to-view-id>payment.xhtml</to-view-id>
		<else>
			<to-view-id>register.xhtml</to-view-id>
	</navigation-case>
   </navigation-rule> 

此外,它还应该包括多重条件检查,就像这样

 <navigation-rule>
	<from-view-id>start.xhtml</from-view-id>
	<navigation-case>
		<from-outcome>payment</from-outcome>
		<if>#{paymentController.orderQty &lt; 100} && #{paymentController.xxx}</if>
			<to-view-id>ordermore.xhtml</to-view-id>
		<else if>#{paymentController.registerCompleted}</else if>
			<to-view-id>payment.xhtml</to-view-id>
		<else>
			<to-view-id>register.xhtml</to-view-id>
	</navigation-case>
   </navigation-rule> 

Thought…
JSF 2 conditional navigation rule, … quite similar with the Spring Web Flow, right? 🙂

下载源代码

Download it – JSF-2-Conditional-Navigation-Example.zip (11KB)Tags : jsf2 navigation rule

相关文章

在 Struts 中配置欢迎页面

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts/configure-a-welcome-page-in-struts/

每个网站都需要一个欢迎页面或默认页面作为入口点。这里有 3 种在 Struts 中配置欢迎页面的方法。

Download this Struts welcome file example – Struts-Welcome-File-Example.zip

1.index.jsp

最简单的方法是创建一个“index.jsp页面,并把它与 WEB-INF 文件夹,项目根文件夹放在同一层。

访问项目根目录

 http://localhost:8080/StrutsExample/ 

它将默认为 index.jsp 内部。

 http://localhost:8080/StrutsExample/index.jsp 

2.web.xml 欢迎文件

在 web.xml 文件中声明一个欢迎文件

 <welcome-file-list>
	<welcome-file>
		/pages/Welcome.jsp
	</welcome-file>
  </welcome-file-list> 

访问项目根目录

 http://localhost:8080/StrutsExample/ 

它将在内部重定向到 welcome.jsp 文件。

 http://localhost:8080/StrutsExample/pages/Welcome.jsp 

web.xml

 <!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Maven Struts Examples</display-name>

  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>
        org.apache.struts.action.ActionServlet
    </servlet-class>
    <init-param>
        <param-name>config</param-name>
        <param-value>
         /WEB-INF/struts-config.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
       <servlet-name>action</servlet-name>
       <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
	<welcome-file>
		/pages/Welcome.jsp
	</welcome-file>
  </welcome-file-list>

</web-app> 

3.JSP 转发

如方法 1 所述,创建一个“index.jsp”文件,并定义一个 JSP forward 标记,将其重定向到另一个 Struts 动作。

index.jsp

声明一个 /Welcome web 路径,用一个 ForwardAction 类型将其转发到另一个 JSP 文件。

struts-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC 
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" 
"http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">

<struts-config>

	<action-mappings>

		<action
			path="/Welcome"
			type="org.apache.struts.actions.ForwardAction"
			parameter="/pages/Welcome.jsp"/>

	</action-mappings>

</struts-config> 

struts welcome page

在 Google App Engine 中配置日志记录

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/configure-logging-in-google-app-engine/

Google App Engine for Java 正在使用 java.util.logging.Logger 来执行日志记录。在本教程中,我们将向您展示如何在 GAE 环境中进行日志记录。

1.日志示例

MovieController中定义一个记录器,并记录不同记录级别(信息、警告和错误)的消息的示例

 import java.util.logging.Logger;
//...

@Controller
@RequestMapping("/movie")
public class MovieController {

	private static final Logger log = Logger.getLogger(MovieController.class.getName());

	@RequestMapping(value="/{name}", method = RequestMethod.GET)
	public String getMovie(@PathVariable String name, ModelMap model) {

	log.info("Information log message.");

        log.warning("Warning log message.");

        log.severe("Error log message.");

	return "page";

	}

} 

2.日志示例

创建一个文件 logging.properties,设置日志级别,并将其放入" $project/war/WEB-INF "

文件:$ project/war/we b-INF/logging . properties

 # Set the default logging level for all loggers to WARNING
.level = WARNING 

3.appengine-web.xml

更新 appengine-web.xml ,定义系统属性标签,将日志指向上面的“we b-INF/logging . properties”。

文件:$ project/war/we b-INF/app engine-WEB . XML

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong-springmvc</application>
  <version>1</version>

  <!-- Configure java.util.logging -->
  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
  </system-properties>

</appengine-web-app> 

4.完成的

在 GAE 本地开发环境中,所有记录的消息都将显示在控制台上。在 GAE 生产环境中,您可以在应用程序的管理员页面中访问记录的消息。

gae java logging

参考

  1. java.util.logging.Logger
  2. GAE 测井

gae logs

在 JSF 2.0 中配置受管 Beans

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/configure-managed-beans-in-jsf-2-0/

在 JSF 2.0 中,可以从 JSF 页面访问的 Java bean 被称为托管 Bean 。受管 bean 可以是一个普通的 Java bean,它包含 getter 和 setter 方法、业务逻辑,甚至是一个后备 bean(一个 bean 包含所有的 HTML 表单值)。

有两种方法可以配置受管 bean:

1.使用注释配置受管 Bean

在 JSF 2.0 中,可以用新的 @ManagedBean 注释来注释受管 Bean。

 package com.mkyong.common;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;

@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
} 

2.用 XML 配置受管 Bean

使用 XML 配置,您可以使用旧的 JSF 1.x 机制在普通的 faces-config.xml 文件中定义受管 bean。

 <?xml version="1.0" encoding="UTF-8"?>
<faces-config

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
    <managed-bean>
	  <managed-bean-name>helloBean</managed-bean-name>
	  <managed-bean-class>com.mkyong.common.HelloBean</managed-bean-class>
	  <managed-bean-scope>session</managed-bean-scope>
     </managed-bean>
</faces-config> 

Best Practice
It’s recommended to put the managed beans in a separate XML file because the faces-config.xml is used to set the application level configurations.

因此,您应该创建一个新的 XML 文件并将受管 beans 细节放入其中,并在javax . faces . config _ FILESinitialize 参数中声明该 XML 文件,该参数位于 WEB-INF/web.xml 文件中。

web.xml

 ...
 <context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>WEB-INF/manage-beans.xml</param-value>
  </context-param>
... 

下载源代码

Download it – JSF-2-Managed-Beans-Example.zip (10KB)Tags : jsf2 managed bean

相关文章

在 Spring MVC 中配置多视图解析器优先级

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/configure-multiple-view-resolvers-priority-in-spring-mvc/

问题

在 Spring MVC 应用程序中,你经常会应用一些视图解析器策略来解析视图名。例如,将三个视图解析器组合在一起:InternalResourceViewResolverResourceBundleViewResolverXmlViewResolver

 <beans ...>
	<bean class="org.springframework.web.servlet.view.XmlViewResolver">
	      <property name="location">
	         <value>/WEB-INF/spring-views.xml</value>
	      </property>
	</bean>

	<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
	      <property name="basename" value="spring-views" />
	</bean>

	<bean id="viewResolver"
	      class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
              <property name="prefix">
                 <value>/WEB-INF/pages/</value>
              </property>
              <property name="suffix">
                 <value>.jsp</value>
              </property>
        </bean>
</beans> 

但是,如果返回一个视图名,将使用哪个视图解析器策略呢?

解决办法

如果应用了多视图解析器策略,您必须通过“ order 属性声明优先级,其中较低的顺序值具有较高的优先级,例如:

 <beans ...>
	<bean class="org.springframework.web.servlet.view.XmlViewResolver">
	     <property name="location">
	        <value>/WEB-INF/spring-views.xml</value>
	     </property>
	     <property name="order" value="0" />
	</bean>

	<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
	     <property name="basename" value="spring-views" />
	     <property name="order" value="1" />
	</bean>

	<bean id="viewResolver"
	      class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
              <property name="prefix">
                 <value>/WEB-INF/pages/</value>
              </property>
              <property name="suffix">
                 <value>.jsp</value>
              </property>
	      <property name="order" value="2" />
        </bean>
</beans> 

现在,如果返回视图名称,视图解析策略按以下顺序工作:

 XmlViewResolver --> ResourceBundleViewResolver --> InternalResourceViewResolver 

Note
The InternalResourceViewResolver must always assign with the lowest priority (largest order number), because it will resolve the view no matter what view name is returned. It caused other view resolvers have no chance to resolve the view if they have lower priority.

下载源代码

Download it – SpringMVC-ViewResolver-Priority-Example.zip (7KB)

参考

  1. Spring MVC InternalResourceViewResolver 示例
  2. Spring MVC XmlViewResolver 示例
  3. Spring MVC ResourceBundleViewResolver 示例

Tags : spring mvc

在 Spring MVC 中配置处理程序映射优先级

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/configure-the-handler-mapping-priority-in-spring-mvc/

通常,在 Spring MVC 开发中,您可能会混合使用多个处理程序映射策略。

例如,使用ControllerClassNameHandlerMapping映射所有的约定处理程序映射,使用 SimpleUrlHandlerMapping 显式映射其他特殊的处理程序映射。

 <beans ...>

   <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
      <property name="mappings">
		<value>
			/index.htm=welcomeController
			/welcome.htm=welcomeController
			/main.htm=welcomeController
			/home.htm=welcomeController
		</value>
      </property>
      <property name="order" value="0" />
   </bean>

   <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
      <property name="caseSensitive" value="true" />
      <property name="order" value="1" />
   </bean>	

   <bean id="welcomeController" 
      class="com.mkyong.common.controller.WelcomeController" />

   <bean class="com.mkyong.common.controller.HelloGuestController" />

</beans> 

在上述情况下,指定处理程序映射优先级很重要,这样就不会导致冲突。您可以通过“ order 属性设置优先级,其中顺序值越低优先级越高。

下载源代码

Download it – SpringMVC-HandlerMapping-Priority-Example.zip (8 KB) ## 参考

  1. ControllerClassNameHandlerMapping 示例
  2. SimpleUrlHandlerMapping 示例

spring mvc (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214230856/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

配置 Struts 标记库

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts/configure-the-struts-tag-libraries/

在 Struts 框架中,您总是需要配置 Struts 标记库,以便在视图页面(JSP)中访问它。有两种方法可以配置它。

1.支柱标记库手动配置

手动配置是古老而经典的方式,在 Struts 版本< = 1.1 和 Servlet < 2.3 容器中使用。下载所有的 Struts 依赖项,确保下面的“ tld 文件被复制到 WEB-INF 文件夹,你可以在下载的 Struts 库中找到这些文件。

  • struts-bean.tld
  • struts-html.tld
  • struts-logic.tld
  • struts-tiles.tld

在 web.xml
web.xml 中声明标记库 uri

 ...
<taglib>
     <taglib-uri>
	  http://struts.apache.org/tags-bean
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-bean.tld
     </taglib-location>
</taglib>
<taglib>
     <taglib-uri>
	  http://struts.apache.org/tags-html
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-html.tld
     </taglib-location>
</taglib>
<taglib>
     <taglib-uri>
	  http://struts.apache.org/tags-logic
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-logic.tld
     </taglib-location>
</taglib>
<taglib>
     <taglib-uri>
	  http://struts.apache.org/tags-tiles
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-tiles.tld
     </taglib-location>
</taglib>
<taglib>
     <taglib-uri>
	  http://struts.apache.org/tags-nested
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-nested.tld
     </taglib-location>
</taglib>
... 

现在您可以在 JSP 页面中访问它。JSP 的 @taglib uri 必须与 web . XML匹配

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

实际上,您可以定义自己的 taglib uri 名称,例如

web.xml

 ...
<taglib>
     <taglib-uri>
	  customer-anything/tags-bean
     </taglib-uri>
     <taglib-location>
	  /WEB-INF/struts-bean.tld
     </taglib-location>
</taglib>
... 

然后通过您的自定义 taglib uri 名称访问它。

<%@ taglib uri="customer-anything/tags-bean" prefix="bean" %>

2.支柱标签库自动配置

这是一种简单的方法,只在 Struts、1.3 和 Servlet 2.3/2.4 容器中使用。您不再需要在 web.xml 中定义“ tlds ”细节,只需要在您的项目类路径中包含 struts-taglib.jar 或者将其复制到 WEB-INF/lib 文件夹中。

所有的“ tld ”细节都在“struts-taglib . jar \ META-INF \ TLD”文件夹中定义。部署过程中, struts-bean.tldstruts-html.tldstruts-logic.tldstruts-tiles.tld 会自动部署。但是,您只能通过下面的“预先固定的 uri ”名称来访问它。在此方法中,不允许您更改“ taglib uri ”名称。

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

常见问题解答

问:看起来“taglib uri”指向 Apache 网站,客户端无法访问互联网怎么办?
A:taglib uri 定义在“struts-taglib . jar \ META-INF \ TLD”文件夹中,它只是一个项目 uri 名称,并不指向 Apache 网站,即使在没有互联网访问的环境下也可以访问。

问:手动配置可以在最新的 Struts 1.2 或 1.3 中工作吗?
A :是的,Struts 是向后兼容的,老办法还是在 Struts 1.2 和 1.3 中支持。

问:哪种方法最好?
A :靠,自动配置只在 Servlet 2.3/2.4 容器中有效。如果让你选择,请转到自动方式,为什么要手动复制 tld 文件?

参考

struts

通过 JDBC 驱动程序连接到 Oracle 数据库

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/jdbc/connect-to-oracle-db-via-jdbc-driver-java/

下面的示例向您展示了如何通过 JDBC 驱动程序连接到 Oracle 数据库。

1.下载 Oracle JDBC 驱动程序

访问甲骨文网站获取甲骨文 JDBC 驱动ojdbc6.jarojdbc7.jar

oracle jdbc driver

另外,您需要创建一个 Oracle 帐户(免费)来下载 JDBC 驱动程序。

2.Java JDBC 连接示例

通过 JDBC 驱动程序连接 Oracle 数据库的代码片段。

 Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = null;
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:SID","username","password");
connection.close(); 

请参见下面的完整示例:

OracleJDBCExample.java

 package com.mkyong;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;

public class OracleJDBCExample {

    public static void main(String[] argv) {

        System.out.println("-------- Oracle JDBC Connection Testing ------");

        try {

            Class.forName("oracle.jdbc.driver.OracleDriver");

        } catch (ClassNotFoundException e) {

            System.out.println("Where is your Oracle JDBC Driver?");
            e.printStackTrace();
            return;

        }

        System.out.println("Oracle JDBC Driver Registered!");

        Connection connection = null;

        try {

            connection = DriverManager.getConnection(
                    "jdbc:oracle:thin:@localhost:1521:xe", "system", "password");

        } catch (SQLException e) {

            System.out.println("Connection Failed! Check output console");
            e.printStackTrace();
            return;

        }

        if (connection != null) {
            System.out.println("You made it, take control your database now!");
        } else {
            System.out.println("Failed to make connection!");
        }
    }

} 

3.运行它

假设OracleJDBCExample.java与 Oracle JDBC 驱动程序ojdbc7.jar一起存储在C:\jdbc-test文件夹中

Terminal

 C:\jdbc-test>javac OracleJDBCExample.java

C:\jdbc-test>java -cp c:\jdbc-test\ojdbc7.jar;c:\jdbc-test OracleJDBCExample
-------- Oracle JDBC Connection Testing ------------
Oracle JDBC Driver Registered!
You made it, take control your database now! 

完成了。

参考

  1. 如何在您的 Maven 本地存储库中添加 Oracle JDBC 驱动程序
  2. OracleDriver 文档

jdbc oracle

Spring 中的构造函数注入类型不明确

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/constructor-injection-type-ambiguities-in-spring/

在 Spring 框架中,当你的类包含多个参数个数相同的构造函数时,总是会导致构造函数注入参数类型歧义的问题。

问题

让我们看看这个客户 bean 的例子。它包含两个构造函数方法,都接受 3 个不同数据类型的参数。

 package com.mkyong.common;

public class Customer 
{
	private String name;
	private String address;
	private int age;

	public Customer(String name, String address, int age) {
		this.name = name;
		this.address = address;
		this.age = age;
	}

	public Customer(String name, int age, String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}
	//getter and setter methods
	public String toString(){
		return " name : " +name + "\n address : "
               + address + "\n age : " + age;
	}

} 

在 Spring bean 配置文件中,为名称传递“mkyong”,为地址传递“188”,为年龄传递“28”。

 <!--Spring-Customer.xml-->
<beans 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="CustomerBean" class="com.mkyong.common.Customer">

		<constructor-arg>
			<value>mkyong</value>
		</constructor-arg>

		<constructor-arg>
			<value>188</value>
		</constructor-arg>

		<constructor-arg>
			<value>28</value>
		</constructor-arg>
        </bean>

</beans> 

运行它,你的预期结果是什么?

 package com.mkyong.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext context = 
    	  new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});

    	Customer cust = (Customer)context.getBean("CustomerBean");
    	System.out.println(cust);
    }
} 

输出

 name : mkyong
 address : 28
 age : 188 

结果并不是我们所期望的,运行的是第二个构造函数,而不是第一个构造函数。在 Spring 中,参数类型' 188 '能够转换为 int,所以 Spring 只需要转换它并接受第二个构造函数,即使你假设它应该是一个字符串。

此外,如果 Spring 不能解析使用哪个构造函数,它将提示以下错误消息

 constructor arguments specified but no matching constructor 
found in bean 'CustomerBean' (hint: specify index and/or 
type arguments for simple parameters to avoid type ambiguities) 

解决办法

要解决这个问题,您应该始终通过 type 属性为构造函数指定确切的数据类型,如下所示:

 <beans 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="CustomerBean" class="com.mkyong.common.Customer">

		<constructor-arg type="java.lang.String">
			<value>mkyong</value>
		</constructor-arg>

		<constructor-arg type="java.lang.String">
			<value>188</value>
		</constructor-arg>

		<constructor-arg type="int">
			<value>28</value>
		</constructor-arg>

	</bean>

</beans> 

再次运行,现在你得到了你所期望的。

输出
 name : mkyong
 address : 188
 age : 28 

Note
It’s always a good practice to explicitly declared the data type for each constructor argument, to avoid constructor injection type ambiguities issue above.spring (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190309054054/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

在 Java 中将 InputStream 转换为 BufferedReader

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/convert-inputstream-to-bufferedreader-in-java/


缓冲阅读器读取字符;而输入流是字节流。

BufferedReader不能直接读取InputStream;所以,我们需要使用像 InputStreamReader 这样的适配器将字节转换成字符格式。例如:

 // BufferedReader -> InputStreamReader -> InputStream
  BufferedReader br = new BufferedReader(
                          new InputStreamReader(inputStream, StandardCharsets.UTF_8)); 

1。从资源文件夹中读取文件。

这个例子从 resources 文件夹中读取一个文件作为InputStream;而且我们可以用BufferedReader + InputStreamReader逐行读取。

InputStreamToReaderExample.java

 package com.mkyong.io.howto;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class InputStreamToReaderExample {

    public static void main(String[] args) throws IOException {

        // loads a file from a resources folder
        InputStream is = InputStreamToReaderExample.class
                            .getClassLoader()
                            .getResourceAsStream("file/abc.txt");

        // BufferedReader -> InputStreamReader -> InputStream

        // try-with-resources, auto close
        String line;
        try (BufferedReader br = new BufferedReader(
                      new InputStreamReader(is, StandardCharsets.UTF_8))) {

            // read line by line
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

        }

    }
} 

2。向 Cloudflare 端点发送 Http post 请求。

这个示例使用 Apache HttpClient 向 Cloudflare 端点发送 POST 请求,以阻止一个 IP 地址。在InputStream中返回的是一个 JSON 字符串,我们可以使用同一个BufferedReader + InputStreamReader来读取字节流。

pom.xml

 <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
  </dependency> 

CloudFlareBanIP.java

 package com.mkyong.security.action;

import com.mkyong.security.util.PropertyUtils;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

public class CloudFlareBanIP {

    private static final String CF_AUTH_EMAIL = PropertyUtils.getInstance().getValue("cf_auth_email");
    private static final String CF_AUTH_TOKEN = PropertyUtils.getInstance().getValue("cf_auth_token");
    private static final String JSON_TYPE = "application/json";
    private static Header[] HTTP_HEADERS = {
            new BasicHeader("X-Auth-Email", CF_AUTH_EMAIL),
            new BasicHeader("X-Auth-Key", CF_AUTH_TOKEN),
            new BasicHeader("content-type", JSON_TYPE)
    };

    private HttpClient httpClient = HttpClientBuilder.create()
            .setConnectionTimeToLive(10, TimeUnit.SECONDS)
            .build();

    public HttpClient getHttpClient() {
        return httpClient;
    }

    public static void main(String[] args) throws IOException {

        CloudFlareBanIP obj = new CloudFlareBanIP();
        String response = obj.banIp("52.249.189.81", "bad ip");

        System.out.println(response);

    }

    public String banIp(String ip, String note) throws IOException {

        StringBuilder json = new StringBuilder();
        json.append("{");
        json.append("\"mode\":\"block\",");
        json.append("\"configuration\":" + "{\"target\":\"ip\",\"value\":\"" + ip + "\"}" + ",");
        json.append("\"notes\":\"" + note + "\"");
        json.append("}");

        StringBuilder result = new StringBuilder();

        HttpPost post = new HttpPost("https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules");
        post.setHeaders(HTTP_HEADERS);
        post.setEntity(new StringEntity(json.toString()));

        // read response from the POST request
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(getHttpClient().execute(post).getEntity().getContent()))) {
            String line;
            while ((line = br.readLine()) != null) {
                result.append(line);
            }
        }

        return result.toString();

    }

} 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ CD Java-io/操作方法

参考文献

在 Java 中将对象转换为 byte[]

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/convert-object-to-byte-in-java/

这篇文章展示了如何在 Java 中将一个对象转换成byte[]或字节数组,反之亦然。

1。将对象转换为字节[]

下面的例子展示了如何使用ByteArrayOutputStreamObjectOutputStream将一个对象转换为byte[]

 // Convert object to byte[]
  public static byte[] convertObjectToBytes(Object obj) {
      ByteArrayOutputStream boas = new ByteArrayOutputStream();
      try (ObjectOutputStream ois = new ObjectOutputStream(boas)) {
          ois.writeObject(obj);
          return boas.toByteArray();
      } catch (IOException ioe) {
          ioe.printStackTrace();
      }
      throw new RuntimeException();
  }

  // Convert object to byte[]
  public static byte[] convertObjectToBytes2(Object obj) throws IOException {
      ByteArrayOutputStream boas = new ByteArrayOutputStream();
      try (ObjectOutputStream ois = new ObjectOutputStream(boas)) {
          ois.writeObject(obj);
          return boas.toByteArray();
      }
  } 

2。将字节[]转换为对象

下面的例子展示了如何使用ByteArrayInputStreamObjectInputStreambyte[]转换回一个对象。

 // Convert byte[] to object
  public static Object convertBytesToObject(byte[] bytes) {
      InputStream is = new ByteArrayInputStream(bytes);
      try (ObjectInputStream ois = new ObjectInputStream(is)) {
          return ois.readObject();
      } catch (IOException | ClassNotFoundException ioe) {
          ioe.printStackTrace();
      }
      throw new RuntimeException();
  }

  // Convert byte[] to object
  public static Object convertBytesToObject2(byte[] bytes)
      throws IOException, ClassNotFoundException {
      InputStream is = new ByteArrayInputStream(bytes);
      try (ObjectInputStream ois = new ObjectInputStream(is)) {
          return ois.readObject();
      }
  }

  // Convert byte[] to object with filter
  public static Object convertBytesToObjectWithFilter(byte[] bytes, ObjectInputFilter filter) {
      InputStream is = new ByteArrayInputStream(bytes);
      try (ObjectInputStream ois = new ObjectInputStream(is)) {

          // add filter before readObject
          ois.setObjectInputFilter(filter);

          return ois.readObject();
      } catch (IOException | ClassNotFoundException ioe) {
          ioe.printStackTrace();
      }
      throw new RuntimeException();
  } 

延伸阅读

下载源代码

$ git 克隆https://github.com/mkyong/core-java.git

$ CD Java-io/com/mkyong/io/object

参考文献

在 Wicket 中创建自定义验证器

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/wicket/create-custom-validator-in-wicket/

在本教程中,您将创建一个自定义密码验证器,并将其附加到密码字段。

请参见创建自定义验证程序的总结步骤:

1.实现IValidator

 import org.apache.wicket.validation.IValidator;

public class StrongPasswordValidator implements IValidator<String>{
	...
} 

2.超越validate(IValidatable <string>validatable)

 public class StrongPasswordValidator implements IValidator<String>{
	...
	@Override
	public void validate(IValidatable<String> validatable) {

		//get input from attached component
		final String field = validatable.getValue();

	}
} 

3.将自定义验证程序附加到表单组件。

 public class CustomValidatorPage extends WebPage {

	public CustomValidatorPage(final PageParameters parameters) {

  	    final PasswordTextField password = new PasswordTextField("password",Model.of(""));
		//attached custom validator to password field
		password.add(new StrongPasswordValidator());

		//...
	}

} 

完整示例

参见下面的 Wicket 示例,创建一个定制的密码验证器,并在密码与预定义的模式不匹配时显示一条错误消息。

1.StrongPasswordValidator

自定义密码验证程序。

 package com.mkyong.user;

import java.util.regex.Pattern;

import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidator;
import org.apache.wicket.validation.ValidationError;

public class StrongPasswordValidator implements IValidator<String> {

	private final String PASSWORD_PATTERN 
                              = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";

	private final Pattern pattern;

	StrongPasswordValidator() {
		pattern = Pattern.compile(PASSWORD_PATTERN);
	}

	@Override
	public void validate(IValidatable<String> validatable) {

		final String password = validatable.getValue();

		// validate password
		if (pattern.matcher(password).matches() == false) {

			//Message from key "StrongPasswordValidator.not-strong-password"
			error(validatable, "not-strong-password");

		}

	}

	private void error(IValidatable<String> validatable, String errorKey) {
		ValidationError error = new ValidationError();
		error.addMessageKey(getClass().getSimpleName() + "." + errorKey);
		validatable.error(error);
	}

} 

文件:package.properties

 StrongPasswordValidator.not-strong-password = Password required at least ... (omitted) 

2.附加到组件

将上述自定义验证程序附加到密码字段。

 package com.mkyong.user;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.model.Model;

public class CustomValidatorPage extends WebPage {

	public CustomValidatorPage(final PageParameters parameters) {

		add(new FeedbackPanel("feedback"));

		final PasswordTextField password 
                                = new PasswordTextField("password",Model.of(""));

		//attached custom validator to password field
		password.add(new StrongPasswordValidator());

		Form<?> form = new Form<Void>("form") {
			@Override
			protected void onSubmit() {
				info("Done");
			}
		};

		add(form);
		form.add(password);

	}

} 
 <html>
<head>
<style>
.feedbackPanelERROR {
	color: red;
}
</style>
</head>
<body>
	<h1>Wicket custom validator example</h1>

	<div wicket:id="feedback"></div>
	<form wicket:id="form">
		<p>
			<label>Password</label>: 
                        <input wicket:id="password" type="password" size="20" />
		</p>
		        <input type="submit" value="Register" />
	</form>

</body>
</html> 

3.演示

开始并访问—http://localhost:8080/wicket examples/

键入弱密码,则从自定义验证程序返回并显示错误消息。

Download it – Wicket-Custom-Validator-Example.zip (9KB)

参考

  1. Wicket IValidator Javadoc
  2. Wicket PasswordTextField 示例
  3. 强密码的正则表达式

validator wicket

JSF 2.0 中的自定义转换器

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/custom-converter-in-jsf-2-0/

在本文中,我们将向您展示如何在 JSF 2.0 中创建自定义转换器。

步骤
1。通过实现javax . faces . convert . converter接口创建一个转换器类。
2。重写 getAsObject()getAsString() 方法。
3。使用 @FacesConverter 注释分配唯一的转换器 ID。
4。通过 f:converter 标签将您的自定义转换器类链接到 JSF 组件。

自定义转换器示例

创建一个名为“URLConverter”的 JSF 2 自定义转换器的详细指南,该转换器用于将字符串转换为 URL 格式(仅在前面添加 HTTP 协议:),并将其存储到一个对象中。

freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });

1.文件夹结构

这个例子的文件夹结构。

jsf2-custom-converter-example-folder

2.转换器类别

通过实现javax . faces . convert . converter接口创建一个自定义转换器类。

 package com.mkyong;

import javax.faces.convert.Converter;
public class URLConverter implements Converter{
	//...
} 

覆盖以下两种方法:
1。,将给定的字符串值转换成一个对象。
2。getAsString() ,将给定对象转换成字符串。

 public class URLConverter implements Converter{

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {

		//...
	}
	@Override
	public String getAsString(FacesContext context, UIComponent component,
			Object value) {

		//...

	} 

使用 @FacesConverter 注释分配转换器 ID。

 package com.mkyong;

import javax.faces.convert.Converter;
@FacesConverter("com.mkyong.URLConverter")
public class URLConverter implements Converter{
	//...
} 

查看完整的自定义转换器源代码:

URLConverter.java

 package com.mkyong;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import org.apache.commons.validator.UrlValidator;

@FacesConverter("com.mkyong.URLConverter")
public class URLConverter implements Converter{

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
		String value) {

		String HTTP = "http://";
		StringBuilder url = new StringBuilder();

		//if not start with http://, then add it
		if(!value.startsWith(HTTP, 0)){
			url.append(HTTP);
		}
		url.append(value);

		//use Apache common URL validator to validate URL
		UrlValidator urlValidator = new UrlValidator();
		//if URL is invalid
		if(!urlValidator.isValid(url.toString())){

			FacesMessage msg = 
				new FacesMessage("URL Conversion error.", 
						"Invalid URL format.");
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			throw new ConverterException(msg);
		}

		URLBookmark urlBookmark = new URLBookmark(url.toString());

		return urlBookmark;
	}

	@Override
	public String getAsString(FacesContext context, UIComponent component,
			Object value) {

		return value.toString();

	}	
} 

在这个自定义的转换器类中,它被赋予一个转换器 id 作为“ com.mkyong.URLConverter ”,并将任何给定的字符串(通过在前面添加“http”)转换成“ URLBookmark 对象。

此外,如果 URL 验证失败,返回一个带有声明的错误消息的 FacesMessage 对象。

URLBookmark.java

 package com.mkyong;

public class URLBookmark{

	String fullURL;

	public URLBookmark(String fullURL) {
		this.fullURL = fullURL;
	}

	public String getFullURL() {
		return fullURL;
	}

	public void setFullURL(String fullURL) {
		this.fullURL = fullURL;
	}

	public String toString(){
		return fullURL;
	}

} 

3.受管 Bean

一个名为“user”的普通托管 bean,这里没什么特别的。

 package com.mkyong;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{

	String bookmarkURL;

	public String getBookmarkURL() {
		return bookmarkURL;
	}

	public void setBookmarkURL(String bookmarkURL) {
		this.bookmarkURL = bookmarkURL;
	}

} 

4.JSF·佩奇

通过“ f:converter ”标记中的“ converterId ”属性将上述自定义转换器链接到 JSF 组件。

default.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      >
    <h:body>

    	<h1>Custom converter in JSF 2.0</h1>

	<h:form>

	  <h:panelGrid columns="3">

		Enter your bookmark URL :

		<h:inputText id="bookmarkURL" value="#{user.bookmarkURL}" 
			size="20" required="true" label="Bookmark URL">
			<f:converter converterId="com.mkyong.URLConverter" />
		</h:inputText>

		<h:message for="bookmarkURL" style="color:red" />

	  </h:panelGrid>

	  <h:commandButton value="Submit" action="result" />

	</h:form>	
    </h:body>
</html> 

result.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jsp/jstl/core"
      >
    <h:body>

    	<h1>Custom converter in JSF 2.0</h1>

	  <h:panelGrid columns="2">

		Bookmark URL :  
		<h:outputText value="#{user.bookmarkURL}" />

	  </h:panelGrid>

    </h:body>
</html> 

5.演示

输入一个有效的 URL,不带“http”。

jsf2-custom-converter-example-1

在有效的 URL 前面添加一个“http”并显示它。

jsf2-custom-converter-example-2

如果提供了无效的 URL,则返回声明的错误消息。

jsf2-custom-converter-example-3

下载源代码

Download It – JSF-2-Custom-Converter-Example.zip (11KB)

参考

  1. J2EE 文档–创建自定义转换器

Tags : jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });

JSF 2.0 中的自定义标签

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/custom-tags-in-jsf-2-0/

在 JSF 2.0 中,您可以创建自定义标签来呈现预定义内容。定制标签看起来像普通的 JSF 标签,使用“ ui:composition ”将内容插入页面。

以下是在 JSF 2.0 中创建自定义标签的步骤概要。

  1. 使用:ui:composition "标记在 XHTML 页面中创建预定义的内容。
  2. 在标记库描述符中声明自定义标记。
  3. 在 web.xml 中注册标记库描述符。

自定义标签示例

创建自定义标签的指南,它将在页面中插入两个预定义的提交和重置按钮。

1.自定义标签

创建一个普通的 XHTML 文件来实现定制标记,它使用“ui:composition”标记将提交和重置按钮组合在一起。

we b-INF/tags/com/mkyong/button . XHTML

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <h:body>
       <ui:composition>

		<h:commandButton type="submit" value="#{buttonSubmitLabel}" />
		<h:commandButton type="reset" value="#{buttonResetLabel}" />

       </ui:composition>
    </h:body>
</html> 

2.标签库

在标记库描述符文件中定义自定义标记细节。

  1. 命名空间–该标签库的命名空间,创建一个唯一的名称以避免冲突。
  2. 标记名–自定义标记名。
  3. –自定义标签的实现。

we b-INF \ mkyong . taglib . XML

 <?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://mkyong.com/facelets</namespace>
    <tag>
	<tag-name>button</tag-name>
	<source>tags/com/mkyong/button.xhtml</source>
    </tag>
</facelet-taglib> 

3.在 web.xml 中注册

在 web.xml 文件中注册标记库。

 <!-- Load custom tag into JSF web application -->
 <context-param>
    <param-name>facelets.LIBRARIES</param-name>
    <param-value>/WEB-INF/mkyong.taglib.xml</param-value>
 </context-param> 

4.使用自定义标签

要使用自定义标签,您必须在顶部声明它的名称空间,并像普通的 JSF 标签一样使用它。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:mkyong="http://mkyong.com/facelets"
      >
    <h:body>
    	<h1>Custome Tags in JSF 2.0</h1>

    	<mkyong:button 
    		buttonSubmitLabel="Submit" 
    		buttonResetLabel="Reset" />

    </h:body>
</html> 

“mkyong:button”自定义标记将呈现一个提交按钮和一个重置按钮。

jsf2-custom-tag--example

下载源代码

Download It – JSF-2-Custom-Tag-Example.zip (11KB)Tags : custom tag jsf2

JSF 2.0 中的自定义验证程序

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/custom-validator-in-jsf-2-0/

在本文中,我们将向您展示如何在 JSF 2.0 中创建一个定制的验证器

步骤

  1. 通过实现javax.faces.validator.Validator接口创建一个验证器类。
  2. 覆盖validate()方法。
  3. 通过@FacesValidator注释分配一个唯一的验证器 ID。
  4. 通过f:validator标签引用自定义验证器类到 JSF 组件。

创建自定义验证器名称“EmailValidator”的详细指南——通过 Java 正则表达式验证电子邮件地址。

1.文件夹结构

该项目的目录结构。

jsf2-custom-validator-folderfreestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });

2.验证程序类

创建一个自定义验证器类并实现javax.faces.validator.Validator接口。

 package com.mkyong;

import javax.faces.validator.Validator;
public class EmailValidator implements Validator{
	//...
} 

覆盖validate()方法。

 public class EmailValidator implements Validator{

	public void validate(FacesContext context, UIComponent component,
			Object value) throws ValidatorException {
		//...
	}
} 

@FacesValidator分配一个唯一的验证器 ID。

 package com.mkyong;

import javax.faces.validator.Validator;

@FacesValidator("com.mkyong.EmailValidator")
public class EmailValidator implements Validator{
	//...
} 

查看完整的自定义验证器类:

EmailValidator.java

 package com.mkyong;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("com.mkyong.EmailValidator")
public class EmailValidator implements Validator{

	private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\." +
			"[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*" +
			"(\\.[A-Za-z]{2,})$";

	private Pattern pattern;
	private Matcher matcher;

	public EmailValidator(){
		  pattern = Pattern.compile(EMAIL_PATTERN);
	}

	@Override
	public void validate(FacesContext context, UIComponent component,
			Object value) throws ValidatorException {

		matcher = pattern.matcher(value.toString());
		if(!matcher.matches()){

			FacesMessage msg = 
				new FacesMessage("E-mail validation failed.", 
						"Invalid E-mail format.");
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			throw new ValidatorException(msg);

		}

	}
} 

上面是一个定制的验证器类,id 为com.mkyong.EmailValidator。如果电子邮件无效,返回FacesMessage错误消息。

Note
For detail explanation about the email regular expression pattern, please refer to this “Validate E-mail with Java regular expression” article.

3.受管 Bean

一个名为“user”的普通托管 bean,这里没什么特别的。

 package com.mkyong;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{

	String email;

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

} 

4.JSF·佩奇

通过f:validator标签中的validatorId属性将上述自定义验证器引用到 JSF 组件。

Spring DI into JSF custom validator
If you need @Autowired into JSF custom validator, uses binding, instead of validatorId. Read this post – Spring @Autowired into JSF custom validator.default.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      >
    <h:body>

    <h1>Custom validator in JSF 2.0</h1>

	  <h:form>

		<h:panelGrid columns="3">

		  Enter your email :

		  <h:inputText id="email" value="#{user.email}" 
			size="20" required="true" label="Email Address">

			<f:validator validatorId="com.mkyong.EmailValidator" />

		  </h:inputText>

		  <h:message for="email" style="color:red" />

		</h:panelGrid>

		<h:commandButton value="Submit" action="result" />

	   </h:form>

    </h:body>
</html> 

result.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      >
    <h:body>

    	<h1>Custom validator in JSF 2.0</h1>

	  <h:panelGrid columns="2">

		Email Address :  
		<h:outputText value="#{user.email}" />

	  </h:panelGrid>

    </h:body>
</html> 

5.演示

通过自定义验证器验证电子邮件地址,如果电子邮件地址无效,返回错误消息。

jsf2-custom-validator-example

下载源代码

Download It – JSF-2-Custom-Validator-Example (10KB)

参考

  1. 使用 Java Regex 进行电子邮件验证
  2. JSF 2.0 中的自定义转换器

Tags : jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });

Spring Security:自定义 403 拒绝访问页面

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-security/customize-http-403-access-denied-page-in-spring-security/

在 Spring Security 中,如果非授权用户试图访问受保护的页面,将显示默认的“ http 403 access denied ”:

spring-security-403-default

在本教程中,我们将向您展示如何在 Spring Security 中自定义 403 访问被拒绝页面。

1.Spring 安全配置

查看配置,如果“alex”试图访问/admin页面,将显示上面的 403 访问被拒绝页面。

Spring-Security.xml

 <http auto-config="true">
	<access-denied-handler error-page="/403" />
	<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
  </http>

  <authentication-manager>
	<authentication-provider>
	  <user-service>
		<user name="alex" password="123456" authorities="ROLE_USER" />
		<user name="mkyong" password="123456" authorities="ROLE_USER, ROLE_ADMIN" />
	  </user-service>
	</authentication-provider>
  </authentication-manager> 

2.解决方案–自定义 403 页面

2.1 创建一个新的 403 页面。

403.jsp

 <html>
<body>
	<h1>HTTP Status 403 - Access is denied</h1>
	<h2>${msg}</h2>
</body>
</html> 

2.2.要显示以上页面,添加一个如下所示的error-page:

Spring-Security.xml

 <http auto-config="true">
		<access-denied-handler error-page="/403" />
		<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
	</http> 

2.3 在控制器类中,添加“/403”URL 的映射:

HelloController.java

 package com.mkyong.web.controller;

import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

	// for 403 access denied page
	@RequestMapping(value = "/403", method = RequestMethod.GET)
	public ModelAndView accesssDenied(Principal user) {

		ModelAndView model = new ModelAndView();

		if (user != null) {
			model.addObject("msg", "Hi " + user.getName() 
			+ ", you do not have permission to access this page!");
		} else {
			model.addObject("msg", 
			"You do not have permission to access this page!");
		}

		model.setViewName("403");
		return model;

	}

} 

完成了。

对于注释用户,使用此.exceptionHandling().accessDeniedPage("/403")

SecurityConfig.java

 package com.mkyong.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {

	 http.authorizeRequests()
	    .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
	    .and().formLogin()
		.loginPage("/login").failureUrl("/login?error")
		.usernameParameter("username")
		.passwordParameter("password")
	    .and().logout().logoutSuccessUrl("/login?logout")
	    .and()
		.exceptionHandling().accessDeniedPage("/403")
	}
} 

3.AccessDeniedHandler

另外,您可以创建一个自定义的AccessDeniedHandler来执行一些业务逻辑,然后将 URL 传递给/403映射。

MyAccessDeniedHandler.java

 package com.mkyong.web.exception;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

public class MyAccessDeniedHandler implements AccessDeniedHandler {

	private String errorPage;

	public MyAccessDeniedHandler() {
	}

	public MyAccessDeniedHandler(String errorPage) {
		this.errorPage = errorPage;
	}

	public String getErrorPage() {
		return errorPage;
	}

	public void setErrorPage(String errorPage) {
		this.errorPage = errorPage;
	}

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
		AccessDeniedException accessDeniedException) 
                throws IOException, ServletException {

		//do some business logic, then redirect to errorPage url
		response.sendRedirect(errorPage);

	}

} 

给 http 标签添加一个ref

Spring-Security.xml

 <http auto-config="true">
		<access-denied-handler ref="my403" />
		<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
	</http>

	<beans:bean id="my403"
		class="com.mkyong.web.exception.MyAccessDeniedHandler">
		<beans:property name="errorPage" value="403" />
	</beans:bean> 

完成了。

4.演示

当“alex”试图访问/admin页面时,将显示上述自定义 403 访问被拒绝页面。

4.1 如果使用error-page,url 将显示如下:

http://localhost:8080/spring-security-403-access-denied/admin

spring-security-403-example1

4.2 如果使用自定义拒绝访问处理程序ref,url 将显示如下:

http://localhost:8080/spring-security-403-access-denied/403

spring-security-403-example2

下载源代码

Download it – spring-security-403-access-denied.zip (26 KB)

参考

  1. StackOverflow:如何用 Spring Security 3.0.x 处理 HTTP 403
  2. Spring Security:AccessDeniedHandler 引用

在 JSF 2.0 中自定义验证错误消息

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/customize-validation-error-message-in-jsf-2-0/

标准 JSF 转换和验证错误消息太详细、太专业,有时不太容易让人理解。在本文中,它向您展示了如何在 JSF 2.0 中定制标准转换或验证错误消息。

概要指南

  1. 从 jsf-api-2.x.jar 的“Messages.properties”文件中找到您的消息密钥。
  2. 创建您自己的属性文件,放置您在上面的“Messages.properties”文件中找到的相同消息键,并用您的自定义错误消息覆盖它。
  3. 在“faces-config.xml”中注册您的属性文件,将其作为应用程序级别。
  4. 完成了。

1.消息.属性

所有 JSF 标准转换和验证错误消息都存储在“Messages.properties”文件中,该文件可以从 jsf-api-2.x.jarjavax \ faces \ messages . properties中找到,见下图:

jsf2-Custom-Validation-Error-Example-1

请参见“ Messages.properties ”文件的一部分

 ...
# ===================================================================
# Converter Errors
# ===================================================================
javax.faces.converter.DateTimeConverter.DATE={2}: ''{0}'' could not be understood as a date.
javax.faces.converter.DateTimeConverter.DATE_detail={2}: ''{0}'' could not be understood as a date. Example: {1} 
...
# ====================================================================
# Validator Errors
# ====================================================================
javax.faces.validator.LengthValidator.MAXIMUM={1}: Validation Error: Length is greater than allowable maximum of ''{0}''
javax.faces.validator.LengthValidator.MINIMUM={1}: Validation Error: Length is less than allowable minimum of ''{0}''
... 

比如
1。<f:validate length minimum = " 5 " maximum = " 10 "/>如果最大长度验证失败,JSF 得到“javax . faces . validator . length validator . maximum”。
如果最小长度验证失败,JSF 得到“javax . faces . validator . length validator . minimum”。

2。<f:convert datetime pattern = " d-M-yyyy "/>
如果日期验证失败,JSF 得到“javax . faces . converter . datetime converter . date _ detail”。

Note
If you do not sure which key match to which validator tag, just display the error message once and compare it with “Messages.properties”, then you will know which key you want to override.freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });

2.自定义错误消息

创建一个名为“ MyMessage.properties ”的属性文件(可以是您喜欢的任何名称),将消息键和自定义错误消息放入其中。稍后,将该属性文件放入项目资源文件夹中。

MyMessage.properties

 javax.faces.converter.DateTimeConverter.DATE={2}: ''{0}'' could not be understood as a date.
javax.faces.converter.DateTimeConverter.DATE_detail=Invalid date format.

javax.faces.validator.LengthValidator.MINIMUM=Minimum length of ''{0}'' is required. 

现在,您将自定义“javax . faces . validator . length validator . minimum”的验证错误消息和“javax . faces . converter . datetime converter . date _ detail”的转换错误消息。

Note
For the XXX_detail message key, you have to override its parent key (summary message) as well, which is XXX without the “_detail” behind; Otherwise, JSF will ignore your new custom error message and keep getting the standard error message from “Messages.properties”, may be this is a bug in JSF 2.0?

3.注册消息包

在“faces-config.xml”中注册您的自定义属性文件,将其作为应用程序级别。

faces-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<faces-config

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
     <application>
	  <message-bundle>
	  	com.mkyong.MyMessage
	  </message-bundle>
     </application>
</faces-config> 

4.演示

一个 JSF 页面,同时添加<f:validate length/><f:convert datetime/>验证。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      >
    <h:body>

    	<h1>Customize validation error message in JSF 2.0</h1>

	<h:form>

		<h:panelGrid columns="3">

			Enter your username :

			<h:inputText id="username" value="#{user.username}" 
				size="20" required="true" label="Username">
				<f:validateLength minimum="5" maximum="10" />
			</h:inputText>

			<h:message for="username" style="color:red" />

			Enter your DOB :

			<h:inputText id="dob" value="#{user.dob}" 
				size="20" required="true" label="Date of Birth">
				<f:convertDateTime />
			</h:inputText>

			<h:message for="dob" style="color:red" />

		</h:panelGrid>

		<h:commandButton value="Submit" action="result" />

	</h:form>	
    </h:body>
</html> 

当验证失败时,现在显示您的自定义错误消息。

jsf2-Custom-Validation-Error-Example-2

下载源代码

Download It – JSF-2-Custom-Validation-Error-Message-Example.zip (11KB)

参考

  1. JSF 2 号&资源包

Tags : error message jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });

在 Tomcat + SSL 连接上部署 JAX-WS web 服务

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat-ssl-connection/

在本文中,我们将向您展示如何在启用了 TLS / SSL 或 https 安全连接的 Tomcat 上部署 JAX-WS web 服务。实际上,答案很简单,只需将它部署为普通的 web 服务,并在 Tomcat 服务器上正确配置 SSL 连接🙂

Note
This article is just a combination of my last few posts on developing web service in SSL connection environment.

1.配置 Tomcat + SSL

有关详细信息,请参见本指南—让 Tomcat 支持 SSL 或 https 连接

基本上,只需从可信的证书提供商那里购买一个证书,或者使用 JDK 的keytool命令为本地主机测试生成一个伪证书。并将以下部分放入您的 Tomcat server.xml文件中。

File:$ Tomcat \ conf \ server . XML

 //...
 <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the 
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->

 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
	       keystoreFile="c:\your keystore file"
	       keystorePass="your keystore password" />
  //... 

重启 Tomcat,现在,你的 Tomcat 支持 SSL 连接,例如 https://localhost:8443

2.部署 Web 服务

像部署一个普通的 web 服务一样部署它,参见本指南—在 Tomcat servlet 容器上部署 JAX-WS web 服务

3.测试一下

配置完成;您可以通过使用普通的 web 服务客户端,在 SSL 连接中访问部署的 web 服务。

举个例子,

 URL url = new URL("https://localhost:8443/HelloWorld/hello?wsdl");
    QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
    Service service = Service.create(url, qname);

    HelloWorld hello = service.getPort(HelloWorld.class);
    System.out.println(hello.getHelloWorldAsString()); 

Note
For localhost SSL testing environment, the client will hit following exceptions, please read the problem and solution below :

  1. Java . security . cert . certificate 异常:找不到与本地主机匹配的名称
  2. SunCertPathBuilderException:无法找到请求目标的有效认证路径

4.完成的

你的 web 服务是在 SSL 保护下的,相当简单,web 服务站点上没有变化;只需将您的 Tomcat 配置为只支持 SSL 连接。

参考

  1. 维基 SSL 连接
  2. JAX-WS 你好世界示例

jQuery 中 filter()和 find()的区别

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/difference-between-filter-and-find-in-jquery/

filter()find() 方法非常相似,只是前者适用于所有元素,而后者只搜索子元素。

太简单了

  1. filter()–搜索所有元素。
  2. find()–仅搜索所有子元素。

jQuery filter()与 find()示例

 <html>
<head>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

<style type="text/css">
	div{
		padding:8px;
		border:1px solid;
	}
</style>

</head>

<body>

<h1>jQuery find() vs filter() example</h1>

<script type="text/javascript">

  $(document).ready(function(){

    $("#filterClick").click(function () {

	$('div').css('background','white');

	$('div').filter('#Fruits').css('background','red');

    });

    $("#findClick").click(function () {

	$('div').css('background','white');

	$('div').find('#Fruits').css('background','red');

    });

  });
</script>
</head><body>

<div id="Fruits">
	Fruits
	<div id="Apple">Apple</div>
	<div id="Banana">Banana</div>
</div>

<div id="Category">
	Category
	<div id="Fruits">Fruits</div>
	<div id="Animals">Animals</div>
</div>

<br/>
<br/>
<br/>

<input type='button' value='filter(Fruits)' id='filterClick'>
<input type='button' value='find(Fruits)' id='findClick'>

</body>
</html> 

http://web.archive.org/web/20200616172522if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-find-filter-example.html

Try DemoTags : jquery jquery traversing

jQuery 中 find()和 children()的区别

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/difference-between-find-and-children-in-jquery/

find()children() 两种方法都用来过滤匹配元素的子元素,只不过前者是向下遍历任意一级,后者是向下遍历单级。

太简单了

  1. find()–搜索匹配元素的子元素、孙元素、曾孙元素…任何下一层。
  2. children()–仅搜索匹配元素的子元素(向下一级)。

参见下面的例子来理解 find()和 children() 之间的区别。

jQuery find() vs children()示例

 <html>
<head>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

<style type="text/css">
	div{
		padding:8px;
		border:1px solid;
	}
</style>

</head>

<body>

<h1>jQuery find() vs children() example</h1>

<script type="text/javascript">

  $(document).ready(function(){

	$("#testChildren").click(function () {

		$('div').css('background','white');

		$('.B1').children('.child').css('background','red');

        });

	$("#testFind").click(function () {

		$('div').css('background','white');

		$('.B1').find('.child').css('background','red');

        });

  });
</script>
</head><body>

<div class="B1">
	<div class="child">B1-1</div>
	<div class="child">B1-2</div>
	<div class="orphan">B1-3 - Orphan</div>
	<div class="child">B1-4</div>

	<div class="B2">
		<div class="child">B2-1</div>
		<div class="child">B2-2</div>
		<div class="orphan">B2-2 - Orphan</div>

		<div class="B3">
			<div class="child">B3-1</div>
			<div class="orphan">B3-2 - Orphan</div>
			<div class="child">B3-3</div>
		</div>
	</div>

</div>

<br/>
<br/>
<br/>

<input type='button' value='.B1 children(child)' id='testChildren'>
<input type='button' value='.B1 find(child)' id='testFind'>

</body>
</html> 

http://web.archive.org/web/20221023054404if_/https://www.mkyong.com/wp-content/uploads/jQuery/jQuery-find-children-example.html

Try Demo

Struts 2 FilterDispatcher 和 StrutsPrepareAndExecuteFilter 的区别?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/struts2/difference-between-struts-2-filterdispatcher-and-strutsprepareandexecutefilter/

问题

在 Struts2 开发中,很多人问为什么有些将 filter 类声明为“filter dispatcher”;还有人声明“strutsprepareendexecutefilter”?但是两者都工作得很好,有什么不同呢?

1。FilterDispatcher 示例

 ...
<filter>
   <filter-name>struts2</filter-name>
   <filter-class>
     org.apache.struts2.dispatcher.FilterDispatcher
   </filter-class>
</filter>

<filter-mapping>
   <filter-name>struts2</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
... 

2。StrutsPrepareAndExecuteFilter 示例

 ...
<filter>
  <filter-name>struts2</filter-name>
  <filter-class>
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
  </filter-class>
</filter>

<filter-mapping>
   <filter-name>struts2</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
... 

回答

FilterDispatcher ( org.apache.struts2.dispatcher.FilterDispatcher)用于早期的 Struts2 开发中,从 Struts 2.1.3 开始就不再使用了。

如果您使用的是 Struts 版本> = 2.1.3,那么总是建议升级新的过滤器类—strutsprepareendexecutefilter(org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter)。

参考

  1. FilterDispatcher 文档
  2. strutsprepareendexecutefilter 文档

struts2

级联和逆之间的不同

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/different-between-cascade-and-inverse/

许多 Hibernate 开发人员对 cascade 选项和 inverse 关键字感到困惑。在某些方面..它们一开始看起来真的很相似,两者都与关系有关。

级联与反向

然而,级联和逆之间没有关系,两者是完全不同的概念。

1.相反的

这用于决定哪一方是管理关系的关系所有者(插入或更新外键列)。

例子

在此示例中,关系所有者属于 stockDailyRecords (inverse=true)。

 <!-- Stock.hbm.xml -->
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" inverse="true">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ... 

当您保存或更新股票对象时

 session.save(stock);
session.update(stock); 

Hibernate 只会插入或更新股票表,不会更新外键列。此处有更多详细示例……

2.串联

在 cascade 中,在一个操作(保存、更新和删除)完成后,它决定是否需要在另一个有关系实体上调用其他操作(保存、更新和删除)。

例子

在本例中,在 stockDailyRecords 上声明了 cascade="save-update"。

 <!-- Stock.hbm.xml -->
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" 
        cascade="save-update" inverse="true">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ... 

当您保存或更新股票对象时

 session.save(stock);
session.update(stock); 

它会将记录插入或更新到股票表中,并在 StockDailyRecord 上调用另一个 insert 或 update 语句(cascade="save-update ")。此处有更多详细示例……

结论

简而言之,“逆向”是决定哪一方将更新外键,而“级联”是决定应该执行什么样的后续操作。两者在关系上看起来很相似,但这完全是两码事。Hibernate 开发人员值得花时间去研究它,因为误解这个概念或误用它会给应用程序带来严重的性能或数据完整性问题。

参考

1.逆= "真"例及解释
2。级联示例–保存、更新和删除

cascade hibernate

jQuery 中 mouseout()和 mouseleave()之间的不同

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/different-between-mouseout-and-mouseleave-in-jquery/

在 jQuery 中,当鼠标离开匹配的元素时,触发 mouseout()mouseleave() 事件。唯一不同的是在子元素中处理“事件冒泡的方式,让我们看两个场景:

1.没有子元素

如果匹配的元素没有子元素,那么 mouseout()mouseleave() 事件的工作方式完全相同。参见下面的“亲自尝试”。

2.内部有子元素

如果匹配的元素有子元素,那么 mouseout()mouseleave() 事件的工作方式是不同的,其方式是“事件冒泡”:

例如,“outerBox”包含一个子元素“innerBox”。

 <div id="outerBox">OuterBox
	<div id="innerBox">InnerBox
	</div>
</div> 

请确保外部盒子和内部盒子都与特定事件相关联。

mouseout()
  1. 当鼠标进入“外部盒子”时,不会触发任何事件。
  2. 当鼠标离开“外部盒子”并进入“内部盒子”时,触发“外部盒子”事件。
  3. 当鼠标离开“innerBox”并进入“outerBox”时,触发“innerBox”事件,然后触发“outerBox”事件。
  4. 当鼠标离开“outerBox”时,触发“outerBox”事件。
鼠标离开()
  1. 当鼠标进入“外部盒子”时,不会触发任何事件。
  2. 当鼠标离开“外部盒子”并进入“内部盒子”时,不会触发任何事件。
  3. 当鼠标离开“内盒”并进入“外盒”时,触发“内盒”事件。
  4. 当鼠标离开“outerBox”时,触发“outerBox”事件。

让我们通过播放下面的例子来理解它:

你自己试试

 <html>
<head>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>

<style type="text/css">
	#mouseout-outerBox1, #mouseleave-outerBox1,
	#mouseout-outerBox2, #mouseleave-outerBox2{
		margin:8px;
		border:1px groove #999966;
		background-color : #999966;
		width:150px;
		height:150px;
		color:white;
	}
	#mouseout-innerBox2, #mouseleave-innerBox2{
		margin:8px 8px 8px 16px;
		border:1px groove #0000FF;
		background-color : #0000FF;
		width:100px;
		height:100px;
		color:white;
	}
	span{
		padding:8px;
	}
	.content{
		width:500px;
		height:250px;
	}
	.container1{
		float:left;
		padding-right:16px;
	}
</style>

</head>
<body>
  <h1>jQuery mouseout() vs mouseleave() example</h1>

<div class="content">
  <div class="container1">
	  <span>mouseout() - no child element</span>
	  <div id="mouseout-outerBox1">OuterBox
	  </div>
	  <span id="mouseout-msg1">#mouseout is fired : 0</span>
  </div>

  <div class="container1">
  	  <span>mouseleave() - no child element</span>
	  <div id="mouseleave-outerBox1">OuterBox
	  </div>
	  <span id="mouseleave-msg1">#mouseleave is fired : 0</span>
  </div>
</div>

<div class="content">
  <div class="container1">
	  <span>mouseout() - with child elements</span>
	  <div id="mouseout-outerBox2">OuterBox
	  	<div id="mouseout-innerBox2">InnerBox
	  	</div>
	  </div>
	  <span id="mouseout-outer-msg2">#mouseout outer is fired : 0</span>
          <br/>
	  <span id="mouseout-inner-msg2">#mouseout inner is fired : 0</span>
  </div>

  <div class="container1">
  	  <span>mouseleave() - with child elements</span>
	  <div id="mouseleave-outerBox2">OuterBox
	  	<div id="mouseleave-innerBox2">InnerBox
	  	</div>
	  </div>
	  <span id="mouseleave-outer-msg2">#mouseleave outer is fired : 0</span>
          <br/>
	  <span id="mouseleave-inner-msg2">#mouseleave inner is fired : 0</span>
  </div>
</div>

<script type="text/javascript">

//example 1
var mouseout1=1;
$('#mouseout-outerBox1').mouseout(function(event) {
  $('#mouseout-msg1').text('#mouseout is fired : ' + mouseout1++)
});

var mouseleave1=1;
$('#mouseleave-outerBox1').mouseleave(function(event) {
  $('#mouseleave-msg1').text('#mouseleave is fired : ' + mouseleave1++)
});

//example 2
var mouseoutouter2=1;
$('#mouseout-outerBox2').mouseout(function(event) {
  $('#mouseout-outer-msg2').text('#mouseout outer is fired : ' + mouseoutouter2++)
});

var mouseoutinner2=1;
$('#mouseout-innerBox2').mouseout(function(event) {
  $('#mouseout-inner-msg2').text('#mouseout inner is fired : ' + mouseoutinner2++)
});

var mouseleaveouter2=1;
$('#mouseleave-outerBox2').mouseleave(function(event) {
  $('#mouseleave-outer-msg2')
         .text('#mouseleave outer is fired : ' + mouseleaveouter2++)
});

var mouseleaveinner2=1;
$('#mouseleave-innerBox2').mouseleave(function(event) {
  $('#mouseleave-inner-msg2')
         .text('#mouseleave inner is fired : ' + mouseleaveinner2++)
});

</script>
</body>
</html> 

http://web.archive.org/web/20190227120536if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-mouseout-mouseleave-example.html

Try Demojquery mouse event

jQuery 中的 mouseover()和 mouseenter()不同

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/different-between-mouseover-and-mouseenter-in-jquery/

在 jQuery 中,当鼠标进入匹配的元素时,触发 mouseover()mouseenter() 事件。唯一不同的是在子元素中处理“事件冒泡的方式,让我们看两个场景:

1.没有子元素

如果匹配的元素没有子元素,那么 mouseover()mouseenter() 事件的工作方式完全相同。参见下面的“亲自尝试”。

2.内部有子元素

如果匹配的元素有子元素,那么 mouseover()mouseenter() 事件的工作方式是不同的,就是“事件冒泡”:

例如,“outerBox”包含一个子元素“innerBox”。

 <div id="outerBox">OuterBox
	<div id="innerBox">InnerBox
	</div>
</div> 

请确保外部盒子和内部盒子都与特定事件相关联。

鼠标悬停()
  1. 当鼠标进入“outerBox”时,触发“outerBox”事件。
  2. 当鼠标进入“innerBox”时,触发“innerBox”事件,然后触发“outerBox”事件。
  3. 当鼠标返回到“外部盒子”时,触发“外部盒子”事件。
滑鼠 enter()
  1. 当鼠标进入“outerBox”时,触发“outerBox”事件。
  2. 当鼠标进入“innerBox”时,触发“innerBox”事件。
  3. 当鼠标回到“外部盒子”时,不会触发任何事件。

雅,这是相当混乱和理解在“话”,让理解它通过播放下面的例子:

你自己试试

 <html>
<head>

<script type="text/javascript" src="jquery-1.4.2.min.js"></script>

<style type="text/css">
	#mouseover-outerBox1, #mouseenter-outerBox1,
	#mouseover-outerBox2, #mouseenter-outerBox2{
		margin:8px;
		border:1px groove #999966;
		background-color : #999966;
		width:150px;
		height:150px;
		color:white;
	}
	#mouseover-innerBox2, #mouseenter-innerBox2{
		margin:8px 8px 8px 16px;
		border:1px groove #0000FF;
		background-color : #0000FF;
		width:100px;
		height:100px;
		color:white;
	}
	span{
		padding:8px;
	}
	.content{
		width:500px;
		height:250px;
	}
	.container1{
		float:left;
		padding-right:16px;
	}
</style>

</head>
<body>
  <h1>jQuery mouseover() vs mouseenter() example</h1>

<div class="content">
  <div class="container1">
	  <span>mouseover() - no child element</span>
	  <div id="mouseover-outerBox1">OuterBox
	  </div>
	  <span id="mouseover-msg1">#mouseover is fired : 0</span>
  </div>

  <div class="container1">
  	  <span>mouseenter() - no child element</span>
	  <div id="mouseenter-outerBox1">OuterBox
	  </div>
	  <span id="mouseenter-msg1">#mouseenter is fired : 0</span>
  </div>
</div>

<div class="content">
  <div class="container1">
	  <span>mouseover() - with child elements</span>
	  <div id="mouseover-outerBox2">OuterBox
	  	<div id="mouseover-innerBox2">InnerBox
	  	</div>
	  </div>
	  <span id="mouseover-outer-msg2">#mouseover outer is fired : 0</span>
          <br/>
	  <span id="mouseover-inner-msg2">#mouseover inner is fired : 0</span>
  </div>

  <div class="container1">
  	  <span>mouseenter() - with child elements</span>
	  <div id="mouseenter-outerBox2">OuterBox
	  	<div id="mouseenter-innerBox2">InnerBox
	  	</div>
	  </div>
	  <span id="mouseenter-outer-msg2">#mouseenter outer is fired : 0</span>
          <br/>
	  <span id="mouseenter-inner-msg2">#mouseenter inner is fired : 0</span>
  </div>
</div>

<script type="text/javascript">

//example 1
var mouseover1=1;
$('#mouseover-outerBox1').mouseover(function(event) {
  $('#mouseover-msg1').text('#mouseover is fired : ' + mouseover1++)
});

var mouseenter1=1;
$('#mouseenter-outerBox1').mouseenter(function(event) {
  $('#mouseenter-msg1').text('#mouseenter is fired : ' + mouseenter1++)
});

//example 2
var mouseoverouter2=1;
$('#mouseover-outerBox2').mouseover(function(event) {
  $('#mouseover-outer-msg2')
              .text('#mouseover outer is fired : ' + mouseoverouter2++)
});

var mouseoverinner2=1;
$('#mouseover-innerBox2').mouseover(function(event) {
  $('#mouseover-inner-msg2')
              .text('#mouseover inner is fired : ' + mouseoverinner2++)
});

var mouseenterouter2=1;
$('#mouseenter-outerBox2').mouseenter(function(event) {
  $('#mouseenter-outer-msg2')
              .text('#mouseenter outer is fired : ' + mouseenterouter2++)
});

var mouseenterinner2=1;
$('#mouseenter-innerBox2').mouseenter(function(event) {
  $('#mouseenter-inner-msg2')
               .text('#mouseenter inner is fired : ' + mouseenterinner2++)
});

</script>
</body>
</html> 

http://web.archive.org/web/20190214231107if_/http://www.mkyong.com/wp-content/uploads/jQuery/jQuery-mouseover-mouseenter-example.html

Try Demojquery mouse movement

session.get()和 session.load()不同

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/different-between-session-get-and-session-load/

很多时候,你会注意到 Hibernate 开发人员混合使用 session.get()session load() ,你想知道有什么不同吗?什么时候你应该使用其中的一个?

session.get()和 session.load()不同

当然,实际上,这两个函数都是用不同的机制来检索一个对象。

1.session.load()

  • 它将总是返回一个“代理”(Hibernate 术语),而不会命中数据库。在 Hibernate 中,代理是一个具有给定标识符值的对象,它的属性还没有初始化,看起来只是一个临时的假对象。
  • 如果没有找到行,它将抛出一个 ObjectNotFoundException

2.session.get()

  • 它总是命中数据库并返回真实对象,一个代表数据库行的对象,而不是代理。
  • 如果没有找到行,它返回空值。

这是性能的问题

Hibernate 创建任何东西都是有原因的,当你做关联的时候,正常的做法是从数据库获取检索一个对象(持久实例)并把它作为一个引用分配给另一个对象,只是为了维护关系。下面我们通过一些例子来了解在什么情况下应该使用 session.load()

1.session.get()

例如,在一个股票应用程序中,股票和 StockTransactions 应该有一个“一对多”的关系,当您想要保存一个股票交易时,通常会声明如下所示的内容

 Stock stock = (Stock)session.get(Stock.class, new Integer(2));
           StockTransaction stockTransactions = new StockTransaction();
           //set stockTransactions detail
           stockTransactions.setStock(stock);        
           session.save(stockTransactions); 

输出

 Hibernate: 
    select ... from mkyong.stock stock0_ 
    where stock0_.STOCK_ID=?
Hibernate: 
    insert into mkyong.stock_transaction (...) 
    values (?, ?, ?, ?, ?, ?) 

在 session.get()中,Hibernate 会命中数据库检索 Stock 对象,并把它作为 StockTransaction 的引用。但是,这个保存过程要求极高,每小时可能有上千或上百万笔交易,你认为有必要打数据库检索股票对象的所有内容保存一条股票交易记录吗?毕竟,您只需要股票的 Id 作为 StockTransaction 的参考。

2.session.load()

在上面的场景中, session.load() 将是您的好解决方案,让我们来看看这个例子。

 Stock stock = (Stock)session.load(Stock.class, new Integer(2));
           StockTransaction stockTransactions = new StockTransaction();
           //set stockTransactions detail
           stockTransactions.setStock(stock);        
           session.save(stockTransactions); 

输出

 Hibernate: 
    insert into mkyong.stock_transaction (...) 
    values (?, ?, ?, ?, ?, ?) 

在 session.load()中,Hibernate 不会命中数据库(输出中没有 select 语句)来检索股票对象,它将返回一个股票代理对象——一个具有给定标识值的假对象。在这种情况下,一个代理对象足以保存股票交易记录。

例外

在例外情况下,请参见示例

session.load()

 Stock stock = (Stock)session.load(Stock.class, new Integer(100)); //proxy

 //initialize proxy, no row for id 100, throw ObjectNotFoundException
System.out.println(stock.getStockCode()); 

它将始终返回一个具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您试图通过从数据库中检索代理的属性来初始化代理时,它将使用 select 语句来访问数据库。如果没有找到行,将抛出一个 ObjectNotFoundException

 org.hibernate.ObjectNotFoundException: No row with the given identifier exists: 
[com.mkyong.common.Stock#100] 

session.get()

 //return null if not found
Stock stock = (Stock)session.get(Stock.class, new Integer(100)); 
System.out.println(stock.getStockCode()); //java.lang.NullPointerException 

如果在数据库中找不到标识值,它将始终返回 null。

结论

没有永远正确的解决方案,您必须了解它们之间的差异,并决定哪种方法最适合您的应用程序。

Tags : hibernate

相关文章

JavaScript 和 JQuery 中函数调用的不同

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/different-call-between-javascript-and-jquery/

这是一个简单的例子,演示了如何在 JavaScript 和 jQuery 中调用一个函数来创建页面加载后的动态内容。

1.Java Script 语言

为了在页面加载后调用函数,JavaScript 使用“ window.onload ”和“ innerHTML ”来动态创建内容。

 window.onload = function(){
 document.getElementById('msgid3')
         .innerHTML = "This is Hello World by JavaScript";
} 

2.jQuery

为了在页面加载后调用函数,jQuery 使用了" $(document)。准备好,和 html() 来动态创建内容。

 $(document).ready(function(){
 $("#msgid1").html("This is Hello World by JQuery 1<BR>");
}); 

例子

 <html>
<head>
<title>jQuery Hello World</title>
</head>
<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<body>

<script type="text/javascript">

$(document).ready(function(){
 $("#msgid1").html("This is Hello World by JQuery 1<BR>");
});

$(function(){
 $("#msgid2").html("This is Hello World by JQuery 2<BR>");
});

window.onload = function(){
 document.getElementById('msgid3').innerHTML = "This is Hello World by JavaScript";
}

</script>

This is Hello World by HTML

<div id="msgid1">
</div>

<div id="msgid2">
</div>

<div id="msgid3">
</div>

</body>
</html> 

jquery-function-call-javascriptfunction javascript

在 Spring Security 中显示自定义错误消息

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-security/display-custom-error-message-in-spring-security/

在 Spring Security 中,当身份验证失败时,将显示以下预定义的错误消息:

 Spring display : Bad credentials 

在本文中,我们将向您展示如何覆盖上述错误消息并显示您自定义的错误消息。举个例子,

 Spring display : Bad credentials
You want override it with this message : Invalid username or password 

解决办法

Spring Security 将消息存储在“ spring-security-core.jar 内的“ messages.properties ”中,见下图:

message.properties

要覆盖它,在 spring securitymessage . properties文件中找到哪个键生成了什么错误消息,并用您自己的属性文件重新定义它。

1.覆盖密钥和消息

创建一个新的属性文件,将其放在项目类路径中,并用您的自定义错误消息覆盖 Spring 的“key”。在这种情况下,只需覆盖“AbstractUserDetailsAuthenticationProvider.badCredentials”。

文件:mymessages.properties

 AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password 

2.注册资源 BundleMessageSource

要加载上述属性文件,请在 Spring bean 配置文件中定义ResourceBundleMessageSource

 <bean id="messageSource"
	class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
	    <list>
		<value>mymessages</value>
	    </list>
	</property>
  </bean> 

现在,当认证失败时,它将显示您自定义的错误消息“无效用户名或密码”,而不是默认的“错误凭证”。

Note
With this trick, you can override any Spring Security messages easily.

下载源代码

Download it – Spring-Security-Display-Custom-Error-Msg.zip (9 KB)spring security

下载/导出 Google 应用程序引擎日志、Java 应用程序

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/download-export-google-app-engine-logs-java-app/

在 GAE,Java App,你可以使用命令" appcfg request_logs "从 GAE 下载或导出日志到你的电脑,见下面签名:

 AppCfg [options] request_logs <app-dir> <output-file> 

您可以输入“ appcfg request_logs ”来查看所有可用选项。

1.什么是<app-dir>

这不是您的 app_id,也不是来自 GAE 的任何已部署的 web 路径,这是您的本地项目文件夹,包含文件:

  1. WEB-INF/appengine-web.xml
  2. WEB-INF/web.xml

GAE Java SDK,命令“ appcfg ”是硬编码的,可以找到上面两个文件。要从 GAE 下载日志,您必须在“ WEB-INF ”文件夹中提供上述两个 XML 文件,这是没有意义的,但您别无选择,只能遵循 GAE 的做法。

在我看来,更好的方法应该是

 AppCfg [options] request_logs <app-id-on-GAE> <output-file> 

Note
If you don’t have the XML files but still want to download the logs, you can issue appcfg download_app to download the deployed application which included the XML files. ## 2.例子

以下是一些从 GAE 下载日志的常见例子。

1.从 GAE 下载今天的日志到“c:\gae.log”。

 C:\appengine-java-sdk-1.6.3.1\bin> 
appcfg request_logs C:\workspace-3.7\SpringGAEProject\war\ c:\gae.log 

2.将 GAE 的所有日志下载到“c:\gae.log”。

 C:\appengine-java-sdk-1.6.3.1\bin>
appcfg --num_days=0 request_logs C:\workspace-3.7\SpringGAEProject\war\ c:\gae.log 

默认情况下,–天数=1

3.将严重性=4 的所有日志从 GAE 下载到“c:\gae.log”。

 C:\appengine-java-sdk-1.6.3.1\bin>
appcfg --num_days=0 --severity=4 request_logs C:\workspace-3.7\SpringGAEProject\war\ c:\gae.log 

P.S Severity 是日志中的记录级别。范围是 0(调试)到 4(关键)。

4.从 GAE 下载所有日志并附加到“c:\gae.log”。

 C:\appengine-java-sdk-1.6.3.1\bin>
appcfg --num_days=0 --append request_logs C:\workspace-3.7\SpringGAEProject\war\ c:\gae.log 

参考

  1. GAE 下载日志文档
  2. 下载应用引擎日志

export gae logs

从谷歌应用引擎(GAE)下载上传的应用程序

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/download-uploaded-application-from-google-app-engine-gae/

您可以使用命令“ appcfg download_app ”从 GAE 下载上传的应用程序,请参见下面的签名:

 AppCfg [options] -A app_id [ -V version ] download_app <out-dir> 

AppCfg 下载示例

假设您已经将 app_id 为" mkyong-springmvc "的应用程序上传到 GAE,要将其下载回您的计算机,请使用以下命令:

 D:\appengine-java-sdk-1.6.3.1\bin>appcfg -A mkyong-springmvc download_app c:\testing 

参见输出:

 D:\appengine-java-sdk-1.6.3.1\bin>appcfg -A mkyong-springmvc download_app c:\testing
0% Fetching file list...
0% Fetching files...
0% [1/43] WEB-INF/lib/repackaged-appengine-tomcat-juli-6.0.29.jar
2% [2/43] WEB-INF/lib/spring-context-3.1.1.RELEASE.jar
4% [3/43] WEB-INF/classes/org/apache/jsp/pages/list_jsp.java
6% [4/43] WEB-INF/classes/META-INF/jdoconfig.xml
9% [5/43] WEB-INF/classes/org/apache/jsp/pages/list_jsp.class
11% [6/43] WEB-INF/lib/repackaged-appengine-jasper-el-6.0.29.jar
13% [7/43] WEB-INF/lib/spring-context-support-3.1.1.RELEASE.jar
16% [8/43] WEB-INF/logging.properties
18% [9/43] WEB-INF/lib/jdo2-api-2.3-eb.jar
20% [10/43] WEB-INF/lib/spring-webmvc-3.1.1.RELEASE.jar
23% [11/43] WEB-INF/lib/repackaged-appengine-jasper-6.0.29.jar
25% [12/43] WEB-INF/lib/repackaged-appengine-ant-1.7.1.jar
27% [13/43] WEB-INF/appengine-web.xml
30% [14/43] WEB-INF/classes/log4j.properties
32% [15/43] WEB-INF/lib/datanucleus-jpa-1.1.5.jar
34% [16/43] WEB-INF/lib/appengine-jsr107cache-1.6.3.1.jar
37% [17/43] WEB-INF/lib/geronimo-jpa_3.0_spec-1.1.1.jar
39% [18/43] WEB-INF/web.xml
41% [19/43] WEB-INF/lib/commons-logging-1.1.1.jar
44% [20/43] WEB-INF/lib/appengine-api-labs-1.6.3.1.jar
46% [21/43] WEB-INF/lib/datanucleus-appengine-1.0.10.final.jar
48% [22/43] WEB-INF/lib/repackaged-appengine-ant-launcher-1.7.1.jar
51% [23/43] WEB-INF/lib/aopalliance-1.0.jar
53% [24/43] favicon.ico
55% [25/43] WEB-INF/lib/repackaged-appengine-jasper-jdt-6.0.29.jar
58% [26/43] WEB-INF/lib/repackaged-appengine-jakarta-jstl-1.1.2.jar
60% [27/43] WEB-INF/lib/spring-expression-3.1.1.RELEASE.jar
62% [28/43] WEB-INF/lib/spring-web-3.1.1.RELEASE.jar
65% [29/43] WEB-INF/lib/spring-aop-3.1.1.RELEASE.jar
67% [30/43] WEB-INF/lib/spring-core-3.1.1.RELEASE.jar
69% [31/43] index.html
72% [32/43] WEB-INF/mvc-dispatcher-servlet.xml
74% [33/43] WEB-INF/lib/repackaged-appengine-jakarta-standard-1.1.2.jar
76% [34/43] WEB-INF/lib/spring-asm-3.1.1.RELEASE.jar
79% [35/43] WEB-INF/lib/datanucleus-core-1.1.5.jar
81% [36/43] WEB-INF/appengine-generated/app.yaml
83% [37/43] pages/list.jsp
86% [38/43] WEB-INF/lib/geronimo-jta_1.1_spec-1.1.1.jar
88% [39/43] WEB-INF/lib/spring-beans-3.1.1.RELEASE.jar
90% [40/43] WEB-INF/lib/jsr107cache-1.1.jar
93% [41/43] WEB-INF/classes/com/mkyong/controller/MovieController.class
95% [42/43] __static__/index.html
97% [43/43] __static__/favicon.ico

download_app completed successfully. 

上面的命令将从 GAE,app_id " mkyong-springmvc "下载所有东西(类,库,jsp)到你的计算机文件夹" c:\testing "。

参考

  1. GAE 命令行参数

gae (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190226092206/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Eclipse IDE:编辑器中不支持的内容类型

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/eclipse/eclipse-ide-unsupported-content-type-in-editor/

问题

使用 Eclipse Ganymede (3.4),开发 JSF 2.0 web 应用程序。然而,当用 Eclipse web 页面编辑器打开 xhtml 文件时,它会提示一个对话框并说…

Unsupported content type in editor
To associate file extension with a supported content type, please see Content Types Preference Page.Eclipse-Unsupported-Content-Type-Error

P . S The。xhtml 文件扩展名是在“内容类型”首选项页面中配置和关联的属性。

解决办法

上千次的尝试和错误,但仍然无法摆脱“不支持的内容类型错误,这可能是由 Eclipse IDE 本身引起的吗?放弃吧,干脆升级到最新日食太阳神 (3.6),马上解决问题😃

Note
Not sure what’s the root cause of it, may be i had installed too many plugins, and some caused the conflicts. Just get a clean copy of the Eclipse IDE will get rid of the annoying error message immediately.eclipse (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190301233143/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Eclipse IDE:。xhtml 代码辅助不适用于 JSF 标签

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/eclipse-ide-xhtml-code-assist-is-not-working-for-jsf-tag/

问题

使用 Eclipse Helios (3.6)开发 JSF 2.0 web 应用程序。在里。xhtml 文件,当我按下“ Ctrl + Space 组合键调用 JSF 标签的代码助手时,没有任何提示?看起来 JSF 标签的代码助手在。xhtml 文件扩展名

eclipse-jsf-support

解决办法

在 Eclipse 项目中,你必须确保项目支持 WTP 和 JSF 功能。

1.右键单击项目,选择 properties,选择“项目 Faces”,确保“ JavaServer Faces ”被选中。稍后,点击进一步配置… 链接来配置 JSF 功能。

eclipse-jsf-support

2.创建一个用户库,包括 JSF API 和实现库, jsf-api-xxx.jarjsf-impl-xxx.jar 。这将为您的项目添加 JSF 功能。

eclipse-jsf-support

3.完成了。xhtml 文件,再次点击" Ctrl +空格键键,现在它提示 JSF 标签代码辅助正确。此外,它增加了 JSF 可视化编辑器的网页编辑器。

eclipse-jsf-support

为 org . Apache . wicket . util . resource 启用调试消息

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/wicket/enable-debug-messages-for-org-apache-wicket-util-resource/

问题

在 Wicket 中,当一个 html 页面没有被找到时,它将为 org . Apache . Wicket . util . resource 发出" Enable debug messages,以获得所有被尝试的文件名的列表。想知道如何为 Wicket 资源启用调试消息吗?

 Root cause:
org.apache.wicket.markup.MarkupNotFoundException: 
Markup of type 'html' for component 'com.mkyong.hello.Hello' not found. 

Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried.: 
[Page class = com.mkyong.hello.Hello, id = 0, version = 0]
at org.apache.wicket.markup.MarkupCache.getMarkupStream(MarkupCache.java:227)
... 

解决办法

我不知道如何在“org.apache.wicket.util.resource”上启用调试,Wicket 错误消息应该更清楚!

或者,您可以在调试模式下启用日志记录,并通过日志文件跟踪 Wicket 如何找到资源。例如,集成 log4j 和 Wicket

log4j 输出的示例…

 DEBUG MarkupCache:300 - Load markup: cacheKey=com.mkyong.hello.Helloen_US.html
DEBUG ResourceStreamLocator:216 - Attempting to locate resource 
'com/mkyong/hello/Hello_en_US.html' on path [folders = [], webapppaths: [/pages/]]

DEBUG ResourceStreamLocator:186 - Attempting to locate resource 
'com/mkyong/hello/Hello_en_US.html' using classloader WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
...
DEBUG ResourceStreamLocator:216 - Attempting to locate resource 
'com/mkyong/hello/Hello.html' on path [folders = [], webapppaths: [/pages/]]
DEBUG ResourceStreamLocator:186 - Attempting to locate resource 
'com/mkyong/hello/Hello.html' using classloader WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
... 

wicket (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225092432/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

在 Quartz 中运行多个作业的示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/example-to-run-multiple-jobs-in-quartz/

在这个例子中,我们展示了如何通过 Quartz APIs、Quartz XML 和 Spring 声明多个 Quartz 作业。在 Quartz 调度框架中,每个作业都将被附加到一个唯一的触发器上,并由调度程序运行。

在 Quartz 中,一个触发器不能用于多个任务。(如果这是错误的,请纠正我。)

1.石英原料药

创建 3 个 Quartz 的作业,JobA,JobB 和 JobC。

 package com.mkyong.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class JobA implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job A is runing");
	}

} 
 package com.mkyong.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class JobB implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job B is runing");
	}

} 
 package com.mkyong.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class JobC implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job C is runing");
	}

} 

使用 Quartz APIs 来声明上述 3 个作业,分配给 3 个特定的触发器并调度它。

 package com.mkyong.quartz;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

public class CronTriggerExample {
	public static void main( String[] args ) throws Exception
    {

	JobKey jobKeyA = new JobKey("jobA", "group1");
    	JobDetail jobA = JobBuilder.newJob(JobA.class)
		.withIdentity(jobKeyA).build();

    	JobKey jobKeyB = new JobKey("jobB", "group1");
    	JobDetail jobB = JobBuilder.newJob(JobB.class)
		.withIdentity(jobKeyB).build();

    	JobKey jobKeyC = new JobKey("jobC", "group1");
    	JobDetail jobC = JobBuilder.newJob(JobC.class)
		.withIdentity(jobKeyC).build();

    	Trigger trigger1 = TriggerBuilder
		.newTrigger()
		.withIdentity("dummyTriggerName1", "group1")
		.withSchedule(
			CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
		.build();

    	Trigger trigger2 = TriggerBuilder
		.newTrigger()
		.withIdentity("dummyTriggerName2", "group1")
		.withSchedule(
			CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
		.build();

    	Trigger trigger3 = TriggerBuilder
		.newTrigger()
		.withIdentity("dummyTriggerName3", "group1")
		.withSchedule(
			CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
		.build();

    	Scheduler scheduler = new StdSchedulerFactory().getScheduler();

    	scheduler.start();
    	scheduler.scheduleJob(jobA, trigger1);
    	scheduler.scheduleJob(jobB, trigger2);
    	scheduler.scheduleJob(jobC, trigger3);

    }
} 

输出

 Job A is runing //every 5 seconds
Job B is runing
Job C is runing
Job A is runing //every 5 seconds
Job B is runing
Job C is runing 

2.Quartz XML 示例

XML 文件中的等效版本。确保“quartz.properties”和“quartz-config.xml”位于项目类路径中。

文件-quartz . properties

 org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin 
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml 
org.quartz.plugin.jobInitializer.failOnFileNotFound = true 

文件–quartz-config . XML

 <?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data

	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData 
        http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
	version="1.8">

	<schedule>
		<job>
			<name>JobA</name>
			<group>GroupDummy</group>
			<description>This is Job A</description>
			<job-class>com.mkyong.quartz.JobA</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameA</name>
				<job-name>JobA</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 5 seconds -->
				<cron-expression>0/5 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>

	<schedule>
		<job>
			<name>JobB</name>
			<group>GroupDummy</group>
			<description>This is Job B</description>
			<job-class>com.mkyong.quartz.JobB</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameB</name>
				<job-name>JobB</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 5 seconds -->
				<cron-expression>0/5 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>
</job-scheduling-data> 

文件:web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<listener>
    <listener-class>
       org.quartz.ee.servlet.QuartzInitializerListener
   </listener-class>
</listener>
</web-app> 

3.春天的例子

春天的对等版本。

 package com.mkyong.job;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class JobA extends QuartzJobBean {

	@Override
	protected void executeInternal(JobExecutionContext arg0)
		throws JobExecutionException {
		System.out.println("Job A is runing");
	}

} 
 package com.mkyong.job;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class JobB extends QuartzJobBean {

	@Override
	protected void executeInternal(JobExecutionContext arg0)
		throws JobExecutionException {
		System.out.println("Job B is runing");

	}

} 
 package com.mkyong.job;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class JobC extends QuartzJobBean {

	@Override
	protected void executeInternal(JobExecutionContext arg0)
		throws JobExecutionException {
		System.out.println("Job C is runing");

	}

} 

文件:Spring-quartz . XML–在 Spring XML bean 配置文件中声明作业和触发器。

 <beans 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="jobA" class="com.mkyong.job.JobA" />
	<bean id="jobB" class="com.mkyong.job.JobB" />
	<bean id="jobC" class="com.mkyong.job.JobC" />

	<!-- Quartz Job -->
	<bean name="JobA" class="org.springframework.scheduling.quartz.JobDetailBean">
		<property name="jobClass" value="com.mkyong.job.JobA" />
	</bean>

	<bean name="JobB" class="org.springframework.scheduling.quartz.JobDetailBean">
		<property name="jobClass" value="com.mkyong.job.JobB" />
	</bean>

	<bean name="JobC" class="org.springframework.scheduling.quartz.JobDetailBean">
		<property name="jobClass" value="com.mkyong.job.JobC" />
	</bean>

	<!-- Cron Trigger, run every 5 seconds -->
	<bean id="cronTriggerJobA" 
                class="org.springframework.scheduling.quartz.CronTriggerBean">
		<property name="jobDetail" ref="JobA" />
		<property name="cronExpression" value="0/5 * * * * ?" />
	</bean>

	<bean id="cronTriggerJobB" 
                class="org.springframework.scheduling.quartz.CronTriggerBean">
		<property name="jobDetail" ref="JobB" />
		<property name="cronExpression" value="0/5 * * * * ?" />
	</bean>

	<bean id="cronTriggerJobC" 
                class="org.springframework.scheduling.quartz.CronTriggerBean">
		<property name="jobDetail" ref="JobC" />
		<property name="cronExpression" value="0/5 * * * * ?" />
	</bean>

	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
			<list>
				<ref bean="cronTriggerJobA" />
				<ref bean="cronTriggerJobB" />
				<ref bean="cronTriggerJobC" />
			</list>
		</property>
	</bean>

</beans> 

运行它

 package com.mkyong.common;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	public static void main(String[] args) throws Exception {
		new ClassPathXmlApplicationContext("Spring-Quartz.xml");

	}
} 

输出。

 INFO: Starting beans in phase 2147483647
Jul 30, 2012 10:38:13 PM org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
INFO: Starting Quartz Scheduler now
Job A is runing
Job B is runing
Job C is runing
Job A is runing
Job B is runing
Job C is runing 

下载源代码

Download it – Multiple-Jobs-in-Quartz-Spring-Example.zip (25kb)

参考

  1. 使用带弹簧的石英

quartz scheduler

fast Json–将 Java 对象转换成 JSON 或从 JSON 转换过来

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/java/fastjson-convert-java-objects-to-from-json/

FastJson 提供了简单的 API 来将 Java 对象与 Json 相互转换

  • JSON.toJSONString–Java 对象到 JSON
  • JSON.parseObject–JSON 到 Java 对象
  • JSON.parseArray–Java 对象列表的 JSON 数组

Note
You may have interest to read this How to parse JSON with Jackson

总的来说,FastJson 非常简单,很容易将 Json 转换成对象,但是,它缺乏直接的File支持,尤其是JSON.parseArray方法,它需要额外的努力来读取 JSON 文件。希望将来像parseObjectparseArray这样的 API 能够直接支持像FileURL这样的源。

PS 用 FastJson 1.2.57 测试

pom.xml

 <dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.57</version>
	</dependency> 

1.波乔

一个简单的 POJO,用于 JSON 转换。

Staff.java

 package com.mkyong;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class Staff {

    private String name;
    private int age;
    private String[] position;
    private List<String> skills;
    private Map<String, BigDecimal> salary;

    //getters, setters, toString, constructor
} 

2.JSON 的 Java 对象

FastJsonExample1.java

 package com.mkyong;

import com.alibaba.fastjson.JSON;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class FastJsonExample1 {

    public static void main(String[] args) {

        Staff staff = createStaff();

        // Java objects to JSON
        String json = JSON.toJSONString(staff);
        System.out.println(json);

        // Java objects to JSON, pretty-print
        String json2 = JSON.toJSONString(staff, true);
        System.out.println(json2);

        // Java objects to JSON, with formatted date
        String json3 = JSON.toJSONStringWithDateFormat(staff, "dd/MM/yyyy HH:mm:ss");
        System.out.println(json3);

        // List of Java objects to JSON Array
        List<Staff> list = Arrays.asList(createStaff(), createStaff());
        String json4 = JSON.toJSONStringWithDateFormat(list, "dd/MM/yyyy HH:mm:ss");
        System.out.println(json4);

        try {
            // can't find fastjson api to write files, np, just use the standard java.nio Files.write
            Files.write(Paths.get("c:\\projects\\staff.json"), json4.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static Staff createStaff() {

        Staff staff = new Staff();

        staff.setName("mkyong");
        staff.setAge(38);
        staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
        Map<String, BigDecimal> salary = new HashMap() {{
            put("2010", new BigDecimal(10000));
            put("2012", new BigDecimal(12000));
            put("2018", new BigDecimal(14000));
        }};
        staff.setSalary(salary);
        staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));
        staff.setJoinDate(new Date());

        return staff;

    }

} 

输出

 // json
{"age":38,"joinDate":1556870430099,"name":"mkyong","position":["Founder","CTO","Writer"],
"salary":{"2018":14000,"2012":12000,"2010":10000},"skills":["java","python","node","kotlin"]}

// json2
{
	"age":38,
	"joinDate":1556870430099,
	"name":"mkyong",
	"position":["Founder","CTO","Writer"],
	"salary":{
		"2018":14000,
		"2012":12000,
		"2010":10000
	},
	"skills":[
		"java",
		"python",
		"node",
		"kotlin"
	]
}

// json3 - format date
{"age":38,"joinDate":"03/05/2019 16:00:30","name":"mkyong","position":["Founder","CTO","Writer"],
"salary":{"2018":14000,"2012":12000,"2010":10000},"skills":["java","python","node","kotlin"]}

// json4 - JSON Array
[
	{
		"age":38,
		"joinDate":1556870630615,
		"name":"mkyong",
		"position":["Founder","CTO","Writer"],
		"salary":{
			"2018":14000,
			"2012":12000,
			"2010":10000
		},
		"skills":[
			"java",
			"python",
			"node",
			"kotlin"
		]
	},
	{
		"age":38,
		"joinDate":1556870630615,
		"name":"mkyong",
		"position":["Founder","CTO","Writer"],
		"salary":{
			"2018":14000,
			"2012":12000,
			"2010":10000
		},
		"skills":[
			"java",
			"python",
			"node",
			"kotlin"
		]
	}
] 

3.JSON 到 Java 对象

FastJsonExample2.java

 package com.mkyong;

import com.alibaba.fastjson.JSON;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FastJsonExample2 {

    public static void main(String[] args) {

        // JSON string to Java object
        String jsonString = "{\"name\":38,\"name\":\"mkyong\"}";
        Staff staff = JSON.parseObject(jsonString, Staff.class);

        System.out.println(staff);

        // JSON array to Java object
        String jsonArray = "[{\"name\":38,\"name\":\"mkyong\"}, {\"name\":39,\"name\":\"mkyong2\"}]";
        List<Staff> staff1 = JSON.parseArray(jsonArray, Staff.class);

        System.out.println(staff1);

        // JSON array in File to Java object
        // staff.json contain JSON array
        try (Stream<String> lines = Files.lines(Paths.get("c:\\projects\\staff.json"))) {

            String content = lines.collect(Collectors.joining());
			// Hope parseArray() will support File or Reader in future.
            List<Staff> list = JSON.parseArray(content, Staff.class);
            System.out.println(list);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
} 

参考

使用 Java 中的 SFTP 进行文件传输(JSch)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/file-transfer-using-sftp-in-java-jsch/

本文展示了如何使用 Java 中的 SSH 文件传输协议(SFTP) 在远程服务器和本地系统之间进行文件传输。

PS 用JSch 0 . 1 . 55测试

1.JSch 依赖性

pom.xml

 <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
  </dependency> 

2.文件传输–JSch 示例

2.1 在JSch中,我们可以使用putget在服务器之间进行文件传输。

我们使用put将文件从本地系统传输到远程服务器。

 channelSftp.put(localFile, remoteFile); 

我们使用get将文件从远程服务器下载到本地系统。

 channelSftp.get(remoteFile, localFile); 

2.2 密码认证。

 JSch jsch = new JSch();
  jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
  jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

  jschSession.setPassword(PASSWORD); 

2.3 公钥和私钥认证,阅读此使用 SSH 的公钥认证

  • 本地私钥-/home/mkyong/.ssh/id_rsa
  • 远程公钥-~/.ssh/authorized_keys
 JSch jsch = new JSch();
  jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
  jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

  jsch.addIdentity("/home/mkyong/.ssh/id_rsa"); 

2.4 查看这个完整的JSch示例,将文件从本地系统传输到远程服务器1.2.3.4,使用 SSH 密码进行身份验证。

SFTPFileTransfer.java

 package com.mkyong.io.howto;

import com.jcraft.jsch.*;

public class SFTPFileTransfer {

    private static final String REMOTE_HOST = "1.2.3.4";
    private static final String USERNAME = "";
    private static final String PASSWORD = "";
    private static final int REMOTE_PORT = 22;
    private static final int SESSION_TIMEOUT = 10000;
    private static final int CHANNEL_TIMEOUT = 5000;

    public static void main(String[] args) {

        String localFile = "/home/mkyong/local/random.txt";
        String remoteFile = "/home/mkyong/remote/afile.txt";

        Session jschSession = null;

        try {

            JSch jsch = new JSch();
            jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
            jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

            // authenticate using private key
            // jsch.addIdentity("/home/mkyong/.ssh/id_rsa");

            // authenticate using password
            jschSession.setPassword(PASSWORD);

            // 10 seconds session timeout
            jschSession.connect(SESSION_TIMEOUT);

            Channel sftp = jschSession.openChannel("sftp");

            // 5 seconds timeout
            sftp.connect(CHANNEL_TIMEOUT);

            ChannelSftp channelSftp = (ChannelSftp) sftp;

            // transfer file from local to remote server
            channelSftp.put(localFile, remoteFile);

            // download file from remote server to local
            // channelSftp.get(remoteFile, localFile);

            channelSftp.exit();

        } catch (JSchException | SftpException e) {

            e.printStackTrace();

        } finally {
            if (jschSession != null) {
                jschSession.disconnect();
            }
        }

        System.out.println("Done");
    }

} 

3.JSch 异常

一些常见的例外。

3.1 对于 UnknownHostKey 异常,将远程 IP 地址添加到known_hosts文件中。

Terminal

 $ ssh-keyscan -t rsa 1.2.3.4 >> ~/.ssh/known_hosts 

3.2 对于无效的私钥,将私钥转换为另一种格式。

Terminal

 $ ssh-keygen -p -f ~/.ssh/id_rsa -m pem 

3.3 对于Auth fail,确保提供的密码正确。

Terminal

 com.jcraft.jsch.JSchException: Auth fail
	at com.jcraft.jsch.Session.connect(Session.java:519)
	at com.mkyong.io.howto.SFTPFileTransfer.main(SFTPFileTransfer.java:34) 

下载源代码

$ git 克隆https://github.com/mkyong/core-java

$ cd java-io

参考

GAE:如何将日志信息输出到文件中

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-how-to-output-log-messages-to-a-file/

默认情况下,所有日志记录消息都将输出到日志控制台。要更改日志设置,找到这个文件—{ Google App Engine SDK directory } \ Google \ App Engine \ tools `dev_appserver_main.py`

File:dev _ appserver _ main . py–查找以下模式

 #...
import getopt
import logging
import os
import signal
import sys
import tempfile
import traceback

logging.basicConfig(
    level=logging.INFO,
    format='%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s] %(message)s')
#... 

输出到文件

为了将日志信息输出到一个文件中,我们可以在dev_appserver_main.py中更改日志记录的配置,如下所示:

 #...
import getopt
import logging
import os
import signal
import sys
import tempfile
import traceback

# default , comment out
#logging.basicConfig(
#    level=logging.INFO,
#    format='%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s] %(message)s')

# new log settings , output to a file
logging.basicConfig(
    filename='/Users/lokjack/gae.log',
    filemode='a', 
    level=logging.DEBUG,
    format='%(levelname)-8s %(asctime)s %(filename)s:%(lineno)s] %(message)s')
#... 

更改dev_appserver_main.py后重启dev_appserver.py

现在,日志控制台不会显示任何日志消息,而是将所有日志消息输出到一个文件中(在本例中,所有日志消息都将输出到" /Users/lokjack/gae.log ")。

Note
This hacks only works on local GAE development environment.

下载源代码

Download it – gae-logging-to-file.zip (11 kb)

参考

  1. 在 Python 中记录到文件
  2. Google App Engine 允许在服务器上创建文件和文件夹吗?

gae logs (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190226091841/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

杰克洛克

Co-founder of penefit.com.

GAE+Java——整合谷歌用户账户

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-java-integrating-google-user-account/

在本教程中,我们将向您展示如何通过 Google Java SDKUserService类将 Google 用户帐户集成到 GAE + Java 项目中。

使用的工具:

  1. JDK 1.6
  2. Eclipse 3.7+Eclipse 的 Google 插件
  3. 谷歌应用引擎 Java SDK 1.6.3.1

1.GAE 用户服务示例

如果用户使用他们的 Google 帐户登录,显示一条欢迎消息和一个“ Logout 链接;否则显示一个“登录链接。

 package com.mkyong.user;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

@SuppressWarnings("serial")
public class LoginExampleServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {

		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();

		resp.setContentType("text/html");
		resp.getWriter().println("<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script><h2>GAE - Integrating Google user account</h2>");

		if (user != null) {

			resp.getWriter().println("Welcome, " + user.getNickname());
			resp.getWriter().println(
				"<a href='"
					+ userService.createLogoutURL(req.getRequestURI())
					+ "'> LogOut </a>");

		} else {

			resp.getWriter().println(
				"Please <a href='"
					+ userService.createLoginURL(req.getRequestURI())
					+ "'> LogIn </a>");

		}
	}
} 

Note
Both login or logout page are handle by GAE automatically, but the workflow is different :

  1. 在本地运行-它将模拟谷歌帐户登录页面(无密码认证)。
  2. 在 GAE 上运行-它将重定向到实际的谷歌帐户登录屏幕。

2.在本地运行

右键单击项目并作为“Web 应用程序”运行。默认情况下,它在 post 8888 上运行。

图 2.1 :访问 URL:http://localhost:8888/log in example

GAE integrating google account and run it local

图 2.2 :一个模拟谷歌的登录界面,输入一些东西,没有认证。

GAE integrating google account and run it local

图 2.3 :欢迎使用,显示注销链接。

GAE integrating google account and run it local

3.部署在 GAE

使用应用程序 ID“mkyong-Java”部署 Google App Engine。

图 3.1–访问网址:http://mkyong-java.appspot.com/loginexample

GAE integrating google account and run it on GAE

图 3.2–重定向至实际的 Google 帐户登录屏幕。

GAE integrating google account and run it on GAE

图 3.3–如果登录成功,重定向回 http://mkyong-java.appspot.com/loginexample

GAE integrating google account and run it on GAE

下载源代码

由于文件很大,所有 GAE SDK 依赖库都被排除在外。

Download it – GAE-UserService-LoginExample.zip (8 KB)

参考

  1. 使用用户服务
  2. 用户 Java API
  3. GAE 用户服务 JavaDoc
  4. GAE Java hello world 示例

gae java (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190226114540/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

GAE+JSF:javax . naming . initial context 是一个受限类

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-jsf-javax-naming-initialcontext-is-a-restricted-class/

问题

使用 Google App Engine (1.6.3)开发 JSF (2.1.7) web 应用程序时,出现以下错误消息:

 java.lang.NoClassDefFoundError: javax.naming.InitialContext is a restricted class. 
	Please see the Google  App Engine developer's guide for more details.
	at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
	at com.sun.faces.config.WebConfiguration.processJndiEntries(WebConfiguration.java:687)
	at com.sun.faces.config.WebConfiguration.<init>(WebConfiguration.java:134)
	at com.sun.faces.config.WebConfiguration.getInstance(WebConfiguration.java:194)
	at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:163)
	//... 

解决办法

谷歌应用引擎不支持 Java clsss-javax.naming.InitialContext,但 JSF 正在WebConfiguration.java中使用它。获得 JSF 源代码的副本,审查方法—processJndiEntries()canProcessJndiEntries()

文件:WebConfiguration.java

 private void processJndiEntries(String contextName) {

		Context initialContext = null;
        try {
            initialContext = new InitialContext();
        } catch (NamingException ne) {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING, ne.toString(), ne);
            }
        }

        if (initialContext != null) {
            // process environment entries
            for (WebEnvironmentEntry entry : WebEnvironmentEntry.values()) {
                String entryName = entry.getQualifiedName();
                String value = null;

                try {
                    value = (String) initialContext.lookup(entryName);
                } catch (NamingException root) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine(root.toString());
                    }
                }

                if (value != null) {
                    if (LOGGER.isLoggable(Level.INFO)) {
                        // special logic for ClientStateSavingPassword
                        if (!entry
                              .equals(WebEnvironmentEntry.ClientStateSavingPassword)) {
                            if (LOGGER
                                  .isLoggable(loggingLevel)) {
                                LOGGER.log(loggingLevel,
                                           "jsf.config.webconfig.enventryinfo",
                                           new Object[]{contextName,
                                                        entryName,
                                                        value});
                            }
                        } else {
                            if (LOGGER
                                  .isLoggable(loggingLevel)) {
                                LOGGER.log(loggingLevel,
                                           "jsf.config.webconfig.enventry.clientencrypt",
                                           contextName);
                            }
                        }
                    }
                    envEntries.put(entry, value);
                }
            }
        }

    }
	private boolean canProcessJndiEntries() {

        try {
            Util.getCurrentLoader(this).loadClass("javax.naming.InitialContext");
        } catch (Exception e) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(
                      "javax.naming is unavailable.  
			JNDI entries related to Mojarra configuration will not be processed.");
            }
            return false;
        }
        return true;

    } 

以上两种方法与 Google App Engine 不兼容。

要解决这个问题,创建一个新的WebConfiguration.java文件,注释上面的方法,并将这个文件放在您的源文件夹中,这样它将重载原来的 JSF WebConfiguration.java。这是一个临时的解决方案,但它很有效,希望 GAE 团队或 JSF 团队将在未来的版本中解决这个问题。

文件:见 WebConfiguration.java 全文

 /*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.faces.config;

import com.sun.faces.lifecycle.HttpMethodRestrictionsPhaseListener;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.faces.application.ResourceHandler;
import javax.faces.application.ViewHandler;
import javax.faces.application.StateManager;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.Util;
import java.util.Collections;

import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import javax.faces.FactoryFinder;
import javax.faces.component.UIInput;
import javax.faces.event.PhaseListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.validator.BeanValidator;
import javax.faces.view.facelets.ResourceResolver;

/** Class Documentation */
public class WebConfiguration {

    // Log instance for this class
    private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();

    // A Simple regular expression of allowable boolean values
    private static final Pattern ALLOWABLE_BOOLEANS =
          Pattern.compile("true|false", Pattern.CASE_INSENSITIVE);

    // Key under which we store our WebConfiguration instance.
    private static final String WEB_CONFIG_KEY =
          "com.sun.faces.config.WebConfiguration";

    // Logging level.  Defaults to FINE
    private Level loggingLevel = Level.FINE;

    private Map<BooleanWebContextInitParameter, Boolean> booleanContextParameters =
          new EnumMap<BooleanWebContextInitParameter, Boolean>(BooleanWebContextInitParameter.class);

    private Map<WebContextInitParameter, String> contextParameters =
          new EnumMap<WebContextInitParameter, String>(WebContextInitParameter.class);

    private Map<WebContextInitParameter, Map<String, String>> facesConfigParameters =
            new EnumMap<WebContextInitParameter, Map<String, String>>(WebContextInitParameter.class);

    private Map<WebEnvironmentEntry, String> envEntries =
          new EnumMap<WebEnvironmentEntry, String>(WebEnvironmentEntry.class);

    private Map<WebContextInitParameter, String []> cachedListParams;

    private Set<String> setParams = new HashSet<String>();

    private ServletContext servletContext;

    private ArrayList<DeferredLoggingAction> deferredLoggingActions;

    private FaceletsConfiguration faceletsConfig;

    // ------------------------------------------------------------ Constructors

    private WebConfiguration(ServletContext servletContext) {

        this.servletContext = servletContext;

        String contextName = getServletContextName();

        initSetList(servletContext);
        processBooleanParameters(servletContext, contextName);
        processInitParameters(servletContext, contextName);
        if (canProcessJndiEntries()) {
            processJndiEntries(contextName);
        }

        // build the cache of list type params
        cachedListParams = new HashMap<WebContextInitParameter, String []>(3);
        getOptionValue(WebContextInitParameter.ResourceExcludes, " ");
        getOptionValue(WebContextInitParameter.DefaultSuffix, " ");
        getOptionValue(WebContextInitParameter.FaceletsViewMappings, ";");

    }

    // ---------------------------------------------------------- Public Methods

    /**
     * Return the WebConfiguration instance for this application passing
     * the result of FacesContext.getCurrentInstance().getExternalContext()
     * to {@link #getInstance(javax.faces.context.ExternalContext)}.
     * @return the WebConfiguration for this application or <code>null</code>
     *  if no FacesContext is available.
     */
    public static WebConfiguration getInstance() {

        FacesContext facesContext = FacesContext.getCurrentInstance();
        return getInstance(facesContext.getExternalContext());

    }

    /**
     * Return the WebConfiguration instance for this application.
     * @param extContext the ExternalContext for this request
     * @return the WebConfiguration for this application
     */
    public static WebConfiguration getInstance(ExternalContext extContext) {

        WebConfiguration config = (WebConfiguration) extContext.getApplicationMap()
              .get(WEB_CONFIG_KEY);
        if (config == null) {
            return getInstance((ServletContext) extContext.getContext());
        } else {
            return config;
        }

    }

    /**
     * Return the WebConfiguration instance for this application.
     * @param servletContext the ServletContext
     * @return the WebConfiguration for this application or <code>null</code>
     *  if no WebConfiguration could be located
     */
    public static WebConfiguration getInstance(ServletContext servletContext) {

        WebConfiguration webConfig = (WebConfiguration)
              servletContext.getAttribute(WEB_CONFIG_KEY);

        if (webConfig == null) {
            webConfig = new WebConfiguration(servletContext);
            servletContext.setAttribute(WEB_CONFIG_KEY, webConfig);
        }
        return webConfig;

    }

    /**
     * @return The <code>ServletContext</code> originally used to construct
     * this WebConfiguration instance
     */
    public ServletContext getServletContext() {

        return servletContext;

    }

    /**
     * Obtain the value of the specified boolean parameter
     * @param param the parameter of interest
     * @return the value of the specified boolean parameter
     */
    public boolean isOptionEnabled(BooleanWebContextInitParameter param) {

        if (booleanContextParameters.get(param) != null) {
            return booleanContextParameters.get(param);
        } else {
            return param.getDefaultValue();
        }

    }

    /**
     * Obtain the value of the specified parameter
     * @param param the parameter of interest
     * @return the value of the specified parameter
     */
    public String getOptionValue(WebContextInitParameter param) {
        String result = contextParameters.get(param);

        if (null == result) {
            WebContextInitParameter alternate = param.getAlternate();
            if (null != alternate) {
                result = contextParameters.get(alternate);
            }
        }

        return result;

    }

    public FaceletsConfiguration getFaceletsConfiguration() {

        if (null == faceletsConfig) {
            faceletsConfig = new FaceletsConfiguration(this);
        }
        return faceletsConfig;

    }

    public Map<String, String> getFacesConfigOptionValue(WebContextInitParameter param, boolean create) {
        Map<String, String> result = null;

        assert(null != facesConfigParameters);

        result = facesConfigParameters.get(param);
        if (null == result) {
            if (create) {
                result = new ConcurrentHashMap<String, String>(3);
                facesConfigParameters.put(param, result);
            } else {
                result = Collections.emptyMap();
            }
        }

        return result;

    }

    public Map<String, String> getFacesConfigOptionValue(WebContextInitParameter param) {
        return getFacesConfigOptionValue(param, false);
    }

    public String[] getOptionValue(WebContextInitParameter param, String sep) {
        String [] result;

        assert(null != cachedListParams);
        if (null == (result = cachedListParams.get(param))) {
            String value = getOptionValue(param);
            if (null == value) {
                result = new String[0];
            } else {
                result = Util.split(value, sep);
            }
            cachedListParams.put(param, result);
        }

        return result;
    }

    /**
     * Obtain the value of the specified env-entry
     * @param entry the env-entry of interest
     * @return the value of the specified env-entry
     */
    public String getEnvironmentEntry(WebEnvironmentEntry entry) {

        return envEntries.get(entry);

    }

    /**
     * @param param the init parameter of interest
     * @return <code>true</code> if the parameter was explicitly set,
     *  otherwise, <code>false</code>
     */
    public boolean isSet(WebContextInitParameter param) {

        return isSet(param.getQualifiedName());

    }

    /**
     * @param param the init parameter of interest
     * @return <code>true</code> if the parameter was explicitly set,
     *  otherwise, <code>false</code>
     */
    public boolean isSet(BooleanWebContextInitParameter param) {

        return isSet(param.getQualifiedName());

    }

    /**
     * @return the name of this application
     */
    public String getServletContextName() {

        if (servletContext.getMajorVersion() == 2
            && servletContext.getMinorVersion() <= 4) {
            return servletContext.getServletContextName();
        } else {
            return servletContext.getContextPath();
        }

    }

    public void overrideContextInitParameter(BooleanWebContextInitParameter param, boolean value) {

        if (param == null) {
            return;
        }
        boolean oldVal = booleanContextParameters.put(param, value);
        if (LOGGER.isLoggable(Level.FINE) && oldVal != value) {
            LOGGER.log(Level.FINE,
                       "Overriding init parameter {0}.  Changing from {1} to {2}.",
                       new Object[] { param.getQualifiedName(), oldVal, value});
        }

    }

    public void overrideContextInitParameter(WebContextInitParameter param, String value) {

        if (param == null || value == null || value.length() == 0) {
            return;
        }
        value = value.trim();
        String oldVal = contextParameters.put(param, value);
        cachedListParams.remove(param);
        if (oldVal != null) {
            if (LOGGER.isLoggable(Level.FINE) && !(oldVal.equals(value))) {
                LOGGER.log(Level.FINE,
                           "Overriding init parameter {0}.  Changing from {1} to {2}.",
                           new Object[]{param.getQualifiedName(),
                                        oldVal,
                                        value});
            }
        }

    }

    public void doPostBringupActions() {

        if (deferredLoggingActions != null) {
            for (DeferredLoggingAction loggingAction : deferredLoggingActions) {
                loggingAction.log();
            }
        }

        // add the HttpMethodRestrictionPhaseListener if the parameter is enabled.
        boolean enabled = this.isOptionEnabled(BooleanWebContextInitParameter.EnableHttpMethodRestrictionPhaseListener);
        if (enabled) {
            LifecycleFactory factory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
            Iterator<String> ids = factory.getLifecycleIds();
            PhaseListener listener = null;
            Lifecycle cur;

            while (ids.hasNext()) {
                cur = factory.getLifecycle(ids.next());
                boolean foundExistingListenerInstance = false;
                for (PhaseListener curListener : cur.getPhaseListeners()) {
                    if (curListener instanceof HttpMethodRestrictionsPhaseListener) {
                        foundExistingListenerInstance = true;
                        break;
                    }
                }
                if (!foundExistingListenerInstance) {
                    if (null == listener) {
                        listener = new HttpMethodRestrictionsPhaseListener();
                    }
                    cur.addPhaseListener(listener);
                }
            }
        }

    }

    // ------------------------------------------------- Package Private Methods

    static void clear(ServletContext servletContext) {

        servletContext.removeAttribute(WEB_CONFIG_KEY);

    }

    // --------------------------------------------------------- Private Methods

    /**
     * <p>Is the configured value valid against the default boolean pattern.</p>
     * @param param the boolean parameter
     * @param value the configured value
     * @return <code>true</code> if the value is valid,
     *  otherwise <code>false</code>
     */
    private boolean isValueValid(BooleanWebContextInitParameter param,
                                 String value) {

        if (!ALLOWABLE_BOOLEANS.matcher(value).matches()) {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING,
                           "jsf.config.webconfig.boolconfig.invalidvalue",
                           new Object[]{
                                 value,
                                 param.getQualifiedName(),
                                 "true|false",
                                 "true|false",
                                 new Boolean(param.getDefaultValue()).toString()
                           });
            }
            return false;
        }

        return true;

    }

    /**
     * <p>Process all boolean context initialization parameters.</p>
     * @param servletContext the ServletContext of interest
     * @param contextName the context name
     */
    private void processBooleanParameters(ServletContext servletContext,
                                          String contextName) {

        // process boolean contxt parameters
        for (BooleanWebContextInitParameter param : BooleanWebContextInitParameter
              .values()) {
            String strValue =
                  servletContext.getInitParameter(param.getQualifiedName());
            boolean value;

            if (strValue != null && strValue.length() > 0 && param.isDeprecated()) {
                BooleanWebContextInitParameter alternate = param.getAlternate();
                if (LOGGER.isLoggable(Level.WARNING)) {
                    if (alternate != null) {
                        queueLoggingAction(new DeferredBooleanParameterLoggingAction(
                              param,
                              Level.WARNING,
                              "jsf.config.webconfig.param.deprecated",
                              new Object[]{
                                    contextName,
                                    param.getQualifiedName(),
                                    alternate.getQualifiedName()}));

                    } else {
                        queueLoggingAction(new DeferredBooleanParameterLoggingAction(
                              param,
                              Level.WARNING,
                              "jsf.config.webconfig.param.deprecated.no_replacement",
                              new Object[]{
                                    contextName,
                                    param.getQualifiedName()}));

                    }
                }

                if (alternate != null) {
                    if (isValueValid(param, strValue)) {
                        value = Boolean.valueOf(strValue);
                    } else {
                        value = param.getDefaultValue();
                    }

                    if (LOGGER.isLoggable(Level.INFO) && alternate != null) {
                        queueLoggingAction(new DeferredBooleanParameterLoggingAction(
                              param,
                              Level.INFO,
                              ((value)
                               ? "jsf.config.webconfig.configinfo.reset.enabled"
                               : "jsf.config.webconfig.configinfo.reset.disabled"),
                              new Object[]{
                                    contextName,
                                    alternate.getQualifiedName()}));
                    }

                    booleanContextParameters.put(alternate, value);
                }
                continue;
            }

            if (!param.isDeprecated()) {
                if (strValue == null) {
                    value = param.getDefaultValue();
                } else {
                    if (isValueValid(param, strValue)) {
                        value = Boolean.valueOf(strValue);
                    } else {
                        value = param.getDefaultValue();
                    }
                }

                // first param processed should be
                // com.sun.faces.displayConfiguration
                if (BooleanWebContextInitParameter.DisplayConfiguration.equals(param) && value) {
                    loggingLevel = Level.INFO;
                }

                if (LOGGER.isLoggable(loggingLevel)) {
                    LOGGER.log(loggingLevel,
                               ((value)
                                ? "jsf.config.webconfig.boolconfiginfo.enabled"
                                : "jsf.config.webconfig.boolconfiginfo.disabled"),
                               new Object[]{contextName,
                                            param.getQualifiedName()});
                }

                booleanContextParameters.put(param, value);
            }

        }

    }

    /**
     * Adds all com.sun.faces init parameter names to a list.  This allows
     * callers to determine if a parameter was explicitly set.
     * @param servletContext the ServletContext of interest
     */
    private void initSetList(ServletContext servletContext) {

        for (Enumeration e = servletContext.getInitParameterNames();
              e.hasMoreElements(); ) {
            String name = e.nextElement().toString();
            if (name.startsWith("com.sun.faces") ||
                  name.startsWith("javax.faces")) {
                setParams.add(name);
            }
        }

    }

    /**
     * @param name the param name
     * @return <code>true</code> if the name was explicitly specified
     */
    private boolean isSet(String name) {

        return setParams.contains(name);

    }

    /**
     * <p>Process all non-boolean context initialization parameters.</p>
     * @param servletContext the ServletContext of interest
     * @param contextName the context name
     */
    private void processInitParameters(ServletContext servletContext,
                                       String contextName) {

        for (WebContextInitParameter param : WebContextInitParameter.values()) {
            String value =
                  servletContext.getInitParameter(param.getQualifiedName());

            if (value != null && value.length() > 0 && param.isDeprecated()) {
                WebContextInitParameter alternate = param.getAlternate();
                DeprecationLoggingStrategy strategy = param.getDeprecationLoggingStrategy();
                if (strategy == null || strategy.shouldBeLogged(this)) {
                    if (LOGGER.isLoggable(Level.WARNING)) {
                        if (alternate != null) {
                            queueLoggingAction(new DeferredParameterLoggingAction(param, Level.WARNING,
                                       "jsf.config.webconfig.param.deprecated",
                                       new Object[]{
                                             contextName,
                                             param.getQualifiedName(),
                                             alternate.getQualifiedName()}));

                        } else {
                            queueLoggingAction(new DeferredParameterLoggingAction(
                                  param,
                                  Level.WARNING,
                                  "jsf.config.webconfig.param.deprecated.no_replacement",
                                  new Object[]{
                                        contextName,
                                        param.getQualifiedName()}));
                        }
                    }
                }

                if (alternate != null) {
                    queueLoggingAction(
                          new DeferredParameterLoggingAction(param,
                                                             Level.INFO,
                                                             "jsf.config.webconfig.configinfo.reset",
                                                             new Object[]{
                                                                    contextName,
                                                                    alternate.getQualifiedName(),
                                                                    value}));

                    contextParameters.put(alternate, value);
                }
                continue;
            }

            if ((value == null || value.length() == 0) && !param.isDeprecated()) {
                value = param.getDefaultValue();
            }
            if (value == null || value.length() == 0) {
                continue;
            }

            if (value.length() > 0) {
                if (LOGGER.isLoggable(loggingLevel)) {
                    LOGGER.log(loggingLevel,
                               "jsf.config.webconfig.configinfo",
                               new Object[]{contextName,
                                            param.getQualifiedName(),
                                            value});

                }
                contextParameters.put(param, value);
            } else {
                if (LOGGER.isLoggable(loggingLevel)) {
                    LOGGER.log(loggingLevel,
                               "jsf.config.webconfig.option.notconfigured",
                               new Object[]{contextName,
                                            param.getQualifiedName()});
                }
            }

        }

    }

    /**
     * <p>Process all JNDI entries.</p>
     * @param contextName the context name
     */
    private void processJndiEntries(String contextName) {

 /* incompatible with Google App Engine
  *   
  *     Context initialContext = null;
        try {
            initialContext = new InitialContext();
        } catch (NamingException ne) {
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.log(Level.WARNING, ne.toString(), ne);
            }
        }

        if (initialContext != null) {
            // process environment entries
            for (WebEnvironmentEntry entry : WebEnvironmentEntry.values()) {
                String entryName = entry.getQualifiedName();
                String value = null;

                try {
                    value = (String) initialContext.lookup(entryName);
                } catch (NamingException root) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine(root.toString());
                    }
                }

                if (value != null) {
                    if (LOGGER.isLoggable(Level.INFO)) {
                        // special logic for ClientStateSavingPassword
                        if (!entry
                              .equals(WebEnvironmentEntry.ClientStateSavingPassword)) {
                            if (LOGGER
                                  .isLoggable(loggingLevel)) {
                                LOGGER.log(loggingLevel,
                                           "jsf.config.webconfig.enventryinfo",
                                           new Object[]{contextName,
                                                        entryName,
                                                        value});
                            }
                        } else {
                            if (LOGGER
                                  .isLoggable(loggingLevel)) {
                                LOGGER.log(loggingLevel,
                                           "jsf.config.webconfig.enventry.clientencrypt",
                                           contextName);
                            }
                        }
                    }
                    envEntries.put(entry, value);
                }
            }
        }
*/
    }

    private boolean canProcessJndiEntries() {

        /* incompatible with Google App Engine
         * try {
            Util.getCurrentLoader(this).loadClass("javax.naming.InitialContext");
        } catch (Exception e) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(
                      "javax.naming is unavailable.  JNDI entries related to Mojarra configuration will not be processed.");
            }
            return false;
        }
        return true;*/

    	if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine(
                  "javax.naming is unavailable.  JNDI entries related to Mojarra configuration will not be processed.");
        }
        return false;

    }

    private void queueLoggingAction(DeferredLoggingAction loggingAction) {

        if (deferredLoggingActions == null) {
            deferredLoggingActions = new ArrayList<DeferredLoggingAction>();
        }
        deferredLoggingActions.add(loggingAction);

    }

    // ------------------------------------------------------------------- Enums

    /**
     * <p>An <code>enum</code> of all non-boolean context initalization parameters
     * recognized by the implementation.</p>
     */
    public enum WebContextInitParameter {

        // implementation note:
        // if a parameter is to be deprecated,
        // then the <name>Deprecated enum element
        // *must* appear after the one that is taking
        // its place.  The reporting logic depends on this

        ManagedBeanFactoryDecorator(
              "com.sun.faces.managedBeanFactoryDecoratorClass",
              ""
        ),
        StateSavingMethod(
              "javax.faces.STATE_SAVING_METHOD",
              "server"
        ),
        FaceletsSuffix(
                ViewHandler.FACELETS_SUFFIX_PARAM_NAME,
                ViewHandler.DEFAULT_FACELETS_SUFFIX
        ),
        DefaultSuffix(
              ViewHandler.DEFAULT_SUFFIX_PARAM_NAME,
              ViewHandler.DEFAULT_SUFFIX
        ),
        JavaxFacesConfigFiles(
              "javax.faces.CONFIG_FILES",
              ""
        ),
        JavaxFacesProjectStage(
              "javax.faces.PROJECT_STAGE",
              "Production"
        ),
        AlternateLifecycleId(
              "javax.faces.LIFECYCLE_ID",
              ""
        ),
        ResourceExcludes(
            ResourceHandler.RESOURCE_EXCLUDES_PARAM_NAME,
            ResourceHandler.RESOURCE_EXCLUDES_DEFAULT_VALUE + " .groovy"
        ),
        NumberOfViews(
              "com.sun.faces.numberOfViewsInSession",
              "15"
        ),
        NumberOfViewsDeprecated(
              "com.sun.faces.NUMBER_OF_VIEWS_IN_SESSION",
              "15",
              true,
              NumberOfViews
        ),
        NumberOfLogicalViews(
              "com.sun.faces.numberOfLogicalViews",
              "15"
        ),
        NumberOfLogicalViewsDeprecated(
              "com.sun.faces.NUMBER_OF_VIEWS_IN_LOGICAL_VIEW_IN_SESSION",
              "15",
              true,
              NumberOfLogicalViews
        ),
        NumberOfConcurrentFlashUsers(
              "com.sun.faces.numberOfConcerrentFlashUsers",
              "5000"
        ),
        NumberOfFlashesBetweenFlashReapings(
              "com.sun.faces.numberOfFlashesBetweenFlashReapings",
              "5000"
        ),
        InjectionProviderClass(
                "com.sun.faces.injectionProvider",
                ""
        ),
        SerializationProviderClass(
              "com.sun.faces.serializationProvider",
              ""
        ),
        ResponseBufferSize(
              "com.sun.faces.responseBufferSize",
              "1024"
        ),
        FaceletsBufferSize(
              "javax.faces.FACELETS_BUFFER_SIZE",
              "1024"
        ),
        FaceletsBufferSizeDeprecated(
              "facelets.BUFFER_SIZE",
              "1024",
              true,
              FaceletsBufferSize,
              new FaceletsConfigParamLoggingStrategy()
        ),
        ClientStateWriteBufferSize(
              "com.sun.faces.clientStateWriteBufferSize",
              "8192"
        ),
        ResourceBufferSize(
            "com.sun.faces.resourceBufferSize",
            "2048"
        ),
        ExpressionFactory(
              "com.sun.faces.expressionFactory",
              "com.sun.el.ExpressionFactoryImpl"
        ),
        ClientStateTimeout(
              "com.sun.faces.clientStateTimeout",
              ""
        ),
        DefaultResourceMaxAge(
              "com.sun.faces.defaultResourceMaxAge",
              "604800000" // 7 days
        ),
        ResourceUpdateCheckPeriod(
              "com.sun.faces.resourceUpdateCheckPeriod",
              "5" // in minutes
        ),
        CompressableMimeTypes(
              "com.sun.faces.compressableMimeTypes",
              ""
        ),
        DisableUnicodeEscaping(
            "com.sun.faces.disableUnicodeEscaping",
            "auto"
        ),
        FaceletsDefaultRefreshPeriod(
              "javax.faces.FACELETS_REFRESH_PERIOD",
              "2"
        ),
        FaceletsDefaultRefreshPeriodDeprecated(
              "facelets.REFRESH_PERIOD",
              "2",
              true,
              FaceletsDefaultRefreshPeriod,
              new FaceletsConfigParamLoggingStrategy()
        ),
        FaceletsResourceResolver(
              ResourceResolver.FACELETS_RESOURCE_RESOLVER_PARAM_NAME,
              ""
        ),
        FaceletsResourceResolverDeprecated(
              "facelets.RESOURCE_RESOLVER",
              "",
              true,
              FaceletsResourceResolver,
              new FaceletsConfigParamLoggingStrategy()
        ),
         FaceletsViewMappings(
              ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME,
              ""
        ),
        FaceletsViewMappingsDeprecated(
              "facelets.VIEW_MAPPINGS",
              "",
              true,
              FaceletsViewMappings,
              new FaceletsConfigParamLoggingStrategy()
        ),
        FaceletsLibraries(
              "javax.faces.FACELETS_LIBRARIES",
              ""
        ),
        FaceletsLibrariesDeprecated(
              "facelets.LIBRARIES",
              "",
              true,
              FaceletsLibraries,
              new FaceletsConfigParamLoggingStrategy()
        ),
        FaceletsDecorators(
              "javax.faces.FACELETS_DECORATORS",
              ""
        ),
        FaceletsDecoratorsDeprecated(
              "facelets.DECORATORS",
              "",
              true,
              FaceletsDecorators,
              new FaceletsConfigParamLoggingStrategy()
        ),
        DuplicateJARPattern(
            "com.sun.faces.duplicateJARPattern",
            ""
        ),
        ValidateEmptyFields(
              UIInput.VALIDATE_EMPTY_FIELDS_PARAM_NAME,
              "auto"
        ),
        FullStateSavingViewIds(
              StateManager.FULL_STATE_SAVING_VIEW_IDS_PARAM_NAME,
              ""
        ),
        AnnotationScanPackages(
              "com.sun.faces.annotationScanPackages",
              ""
        ),
        FaceletFactory(
              "com.sun.faces.faceletFactory",
              ""
        ),
        FaceletCache(
            "com.sun.faces.faceletCache",
            ""
        ),
        FaceletsProcessingFileExtensionProcessAs(
                "",
                ""
        );

        private String defaultValue;
        private String qualifiedName;
        private WebContextInitParameter alternate;
        private boolean deprecated;
        private DeprecationLoggingStrategy loggingStrategy;

    // ---------------------------------------------------------- Public Methods

        public String getDefaultValue() {

            return defaultValue;

        }

        public String getQualifiedName() {

            return qualifiedName;

        }

        DeprecationLoggingStrategy getDeprecationLoggingStrategy() {

            return loggingStrategy;

        }

    // ------------------------------------------------- Package Private Methods

        WebContextInitParameter(String qualifiedName,
                                String defaultValue) {

            this(qualifiedName, defaultValue, false, null);

        }

        WebContextInitParameter(String qualifiedName,
                                String defaultValue,
                                boolean deprecated,
                                WebContextInitParameter alternate) {

            this.qualifiedName = qualifiedName;
            this.defaultValue = defaultValue;
            this.deprecated = deprecated;
            this.alternate = alternate;

        }

        WebContextInitParameter(String qualifiedName,
                                String defaultValue,
                                boolean deprecated,
                                WebContextInitParameter alternate,
                                DeprecationLoggingStrategy loggingStrategy) {

            this(qualifiedName, defaultValue, deprecated, alternate);
            this.loggingStrategy = loggingStrategy;

        }

    // --------------------------------------------------------- Private Methods

        private WebContextInitParameter getAlternate() {

            return alternate;

        }

        private boolean isDeprecated() {

            return deprecated;

        }

    }

    /**
     * <p>An <code>enum</code> of all boolean context initalization parameters
     * recognized by the implementation.</p>
     */
    public enum BooleanWebContextInitParameter {

        // implementation note:
        // if a parameter is to be deprecated,
        // then the <name>Deprecated enum element
        // *must* appear after the one that is taking
        // its place.  The reporting logic depends on this

        DisplayConfiguration(
              "com.sun.faces.displayConfiguration",
              false
        ),
        ValidateFacesConfigFiles(
              "com.sun.faces.validateXml",
              false
        ),
        VerifyFacesConfigObjects(
              "com.sun.faces.verifyObjects",
              false
        ),
        ForceLoadFacesConfigFiles(
              "com.sun.faces.forceLoadConfiguration",
              false
        ),
        DisableArtifactVersioning(
              "com.sun.faces.disableVersionTracking",
              false,
              true,
              null
        ),
        EnableHtmlTagLibraryValidator(
              "com.sun.faces.enableHtmlTagLibValidator",
              false
        ),
        EnableCoreTagLibraryValidator(
              "com.sun.faces.enableCoreTagLibValidator",
              false
        ),
        PreferXHTMLContentType(
              "com.sun.faces.preferXHTML",
              false
        ),
        PreferXHTMLContextTypeDeprecated(
              "com.sun.faces.PreferXHTML",
              false,
              true,
              PreferXHTMLContentType
        ),
        CompressViewState(
              "com.sun.faces.compressViewState",
              true
        ),
        CompressViewStateDeprecated(
              "com.sun.faces.COMPRESS_STATE",
              true,
              true,
              CompressViewState
        ),
        CompressJavaScript(
            "com.sun.faces.compressJavaScript",
            true
        ),
        ExternalizeJavaScriptDeprecated(
            "com.sun.faces.externalizeJavaScript",
            true,
            true,
            null
        ),
        SendPoweredByHeader(
              "com.sun.faces.sendPoweredByHeader",
              true
        ),
        EnableJSStyleHiding(
            "com.sun.faces.enableJSStyleHiding",
             false
        ),
        EnableScriptInAttributeValue(
            "com.sun.faces.enableScriptsInAttributeValues",
             true
        ),
        WriteStateAtFormEnd(
            "com.sun.faces.writeStateAtFormEnd",
            true
        ),
        EnableLazyBeanValidation(
             "com.sun.faces.enableLazyBeanValidation",
             true
        ),
        EnableLoadBundle11Compatibility(
             "com.sun.faces.enabledLoadBundle11Compatibility",
             false
        ),
        EnableRestoreView11Compatibility(
              "com.sun.faces.enableRestoreView11Compatibility",
              false
        ),
        SerializeServerState(
              "com.sun.faces.serializeServerState",
              false
        ),
        EnableViewStateIdRendering(
            "com.sun.faces.enableViewStateIdRendering",
            true
        ),
        RegisterConverterPropertyEditors(
            "com.sun.faces.registerConverterPropertyEditors",
            false
        ),
        EnableGroovyScripting(
            "com.sun.faces.enableGroovyScripting",
            false
        ),
        DisableFaceletJSFViewHandler(
              "javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER",
              false
        ),
        DisableDefaultBeanValidator(
                BeanValidator.DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME,
                false),
        DateTimeConverterUsesSystemTimezone(
              "javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE",
              false
        ),
        EnableHttpMethodRestrictionPhaseListener(
              "com.sun.faces.ENABLE_HTTP_METHOD_RESTRICTION_PHASE_LISTENER",
              false
        ),
        FaceletsSkipComments(
              "javax.faces.FACELETS_SKIP_COMMENTS",
              false
        ),
        FaceletsSkipCommentsDeprecated(
              "facelets.SKIP_COMMENTS",
              false,
              true, 
              FaceletsSkipComments,
              new FaceletsConfigParamLoggingStrategy()
        ),
        PartialStateSaving(
              StateManager.PARTIAL_STATE_SAVING_PARAM_NAME,
              true
        ),
        GenerateUniqueServerStateIds(
              "com.sun.faces.generateUniqueServerStateIds",
              true
        ),
        AutoCompleteOffOnViewState(
              "com.sun.faces.autoCompleteOffOnViewState",
              true
        ),
        EnableThreading(
              "com.sun.faces.enableThreading",
              false
        ),
        AllowTextChildren(
            "com.sun.faces.allowTextChildren",
            false
        ),
        CacheResourceModificationTimestamp(
              "com.sun.faces.cacheResourceModificationTimestamp",
              false
        ),
        EnableAgressiveSessionDirtying(
              "com.sun.faces.enableAgressiveSessionDirtying",
              false
        ),
        EnableMissingResourceLibraryDetection(
              "com.sun.faces.enableMissingResourceLibraryDetection",
              false
        );

        private BooleanWebContextInitParameter alternate;

        private String qualifiedName;
        private boolean defaultValue;
        private boolean deprecated;
        private DeprecationLoggingStrategy loggingStrategy;

    // ---------------------------------------------------------- Public Methods

        public boolean getDefaultValue() {

            return defaultValue;

        }

        public String getQualifiedName() {

            return qualifiedName;

        }

        DeprecationLoggingStrategy getDeprecationLoggingStrategy() {

            return loggingStrategy;

        }

    // ------------------------------------------------- Package Private Methods

        BooleanWebContextInitParameter(String qualifiedName,
                                       boolean defaultValue) {

            this(qualifiedName, defaultValue, false, null);

        }

        BooleanWebContextInitParameter(String qualifiedName,
                                       boolean defaultValue,
                                       boolean deprecated,
                                       BooleanWebContextInitParameter alternate) {

            this.qualifiedName = qualifiedName;
            this.defaultValue = defaultValue;
            this.deprecated = deprecated;
            this.alternate = alternate;

        }

        BooleanWebContextInitParameter(String qualifiedName,
                                      boolean defaultValue,
                                      boolean deprecated,
                                      BooleanWebContextInitParameter alternate,
                                      DeprecationLoggingStrategy loggingStrategy) {

            this(qualifiedName, defaultValue, deprecated, alternate);
            this.loggingStrategy = loggingStrategy;

        }

    // --------------------------------------------------------- Private Methods

        private BooleanWebContextInitParameter getAlternate() {

            return alternate;

        }

        private boolean isDeprecated() {

            return deprecated;

        }

    }

    /**
     * <p>An <code>enum</code> of all environment entries (specified in the
     * web.xml) recognized by the implemenetation.</p>
     */
    public enum WebEnvironmentEntry {

        ClientStateSavingPassword("ClientStateSavingPassword"),
        ProjectStage(javax.faces.application.ProjectStage.PROJECT_STAGE_JNDI_NAME);

        private static final String JNDI_PREFIX = "java:comp/env/";
        private String qualifiedName;

    // ---------------------------------------------------------- Public Methods

         public String getQualifiedName() {

            return qualifiedName;

        }

    // ------------------------------------------------- Package Private Methods

        WebEnvironmentEntry(String qualifiedName) {

            if (qualifiedName.startsWith(JNDI_PREFIX)) {
                this.qualifiedName = qualifiedName;
            } else {
                this.qualifiedName = JNDI_PREFIX + qualifiedName;
            }

        }

    }

    /**
     * <p>An <code>enum</code> of all possible values for the <code>disableUnicodeEscaping</code>
     * configuration parameter.</p>
     */
    public enum DisableUnicodeEscaping {
        True("true"),
        False("false"),
        Auto("auto");

        private final String value;

        DisableUnicodeEscaping(String value) {
            this.value = value;
        }

        public static DisableUnicodeEscaping getByValue(String value)
        {
            for (DisableUnicodeEscaping disableUnicodeEscaping : DisableUnicodeEscaping.values()) {
                if (disableUnicodeEscaping.value.equals(value)) {
                    return disableUnicodeEscaping;
                }
            }

            return null;
        }
    }

    // ----------------------------------------------------------- Inner Classes

    private interface DeprecationLoggingStrategy {

        boolean shouldBeLogged(WebConfiguration configuration);

    }

    private static class FaceletsConfigParamLoggingStrategy implements DeprecationLoggingStrategy {

        public boolean shouldBeLogged(WebConfiguration configuration) {
            return !configuration.isOptionEnabled(BooleanWebContextInitParameter.DisableFaceletJSFViewHandler);
        }

    } // END FaceletsConfigParamLoggingStrategy

    private interface DeferredLoggingAction {

        void log();

    } // END DeferredLogginAction

    private class DeferredParameterLoggingAction implements DeferredLoggingAction {

        private WebContextInitParameter parameter;
        private Level loggingLevel;
        private String logKey;
        private Object[] params;

        DeferredParameterLoggingAction(WebContextInitParameter parameter,
                                       Level loggingLevel,
                                       String logKey,
                                       Object[] params) {

            this.parameter = parameter;
            this.loggingLevel = loggingLevel;
            this.logKey = logKey;
            this.params = params;

        }

        public void log() {

            if (WebConfiguration.LOGGER.isLoggable(loggingLevel)) {
                DeprecationLoggingStrategy strategy = parameter.getDeprecationLoggingStrategy();
                if (strategy != null && strategy.shouldBeLogged(WebConfiguration.this)) {
                    WebConfiguration.LOGGER.log(loggingLevel, logKey, params);
                }
            }

        }

    } // END DeferredParameterLogginAction

    private class DeferredBooleanParameterLoggingAction implements DeferredLoggingAction {

        private BooleanWebContextInitParameter parameter;
        private Level loggingLevel;
        private String logKey;
        private Object[] params;

        DeferredBooleanParameterLoggingAction(BooleanWebContextInitParameter parameter,
                                              Level loggingLevel,
                                              String logKey,
                                              Object[] params) {
            this.parameter = parameter;
            this.loggingLevel = loggingLevel;
            this.logKey = logKey;
            this.params = params;
        }

        public void log() {

            if (WebConfiguration.LOGGER.isLoggable(loggingLevel)) {
                DeprecationLoggingStrategy strategy = parameter.getDeprecationLoggingStrategy();
                if (strategy != null && strategy.shouldBeLogged(WebConfiguration.this)) {
                    WebConfiguration.LOGGER.log(loggingLevel, logKey, params);
                }
            }

        }

    } // END DeferredBooleanParameterLoggingAction

} // END WebConfiguration 

Credit : Source code is copied from here ## 参考

  1. 为 GAE 修改 WebConfiguration.java
  2. Mojarra JSF 2.0 RC2 和谷歌应用引擎 SDK 1.2.6

gae jsf2

GAE + JSF:无法实例化 expression factory“com . sun . El . expression factory impl”

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-jsf-unable-to-instantiate-expressionfactory-com-sun-el-expressionfactoryimpl/

问题

JSF 应用程序能够部署在本地 GAE 环境中,开发环境如下:

  1. JSF 2.1.7
  2. 谷歌应用引擎 SDK 1.6.3

但是在 GAE 生产环境中部署时出现错误消息。下面是 GAE 记录的错误消息。

 com.sun.faces.config.ConfigureListener installExpressionFactory: Unable to instantiate ExpressionFactory 'com.sun.el.ExpressionFactoryImpl'
E 2012-04-24 03:37:37.989
com.sun.faces.config.ConfigureListener contextInitialized: Critical error during deployment: 
com.sun.faces.config.ConfigurationException: 
	It appears the JSP version of the container is older than 2.1 and unable to locate the EL RI expression factory, 
	com.sun.el.ExpressionFactoryImpl.  If not using JSP or the EL RI, make sure the context initialization parameter, 
	com.sun.faces.expressionFactory, is properly set.

	at com.sun.faces.config.ConfigureListener.registerELResolverAndListenerWithJsp(ConfigureListener.java:662)
	at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:243)
	at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548)
	at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
	at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
	at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
	at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:202)
	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:171)
	at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:123)
	at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
	at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:449)
	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:455)
	at com.google.tracing.TraceContext.runInContext(TraceContext.java:695)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:333)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:325)
	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:453)
	at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
	at java.lang.Thread.run(Thread.java:679) 

解决办法

GAE + JSF 需要 el-ri.jar 。要解决它,找到并获取 el-ri.jar ,并将其复制到您的“ /war/lib ”文件夹中。

Where to get el-ri.jar?
The faster way is get the el-ri.jar from Maven repository. ## 参考

  1. 搜索 Maven 知识库
  2. 带有 JSF2、CDI 的谷歌应用引擎

gae jsf2

GAE + JSF:无法恢复 View /hello.xhtml

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-jsf-view-hello-xhtml-could-not-be-restored/

问题

部署在 GAE 生产环境中,当从一个页面/视图导航到另一个页面/视图时,GAE 显示错误消息“视图 xxx 无法恢复”?

  1. JSF 2.1.7
  2. 谷歌应用引擎 SDK 1.6.3

view can not be restored

在 GAE 当地发展没有问题。

解决办法

默认情况下,JSF 2 使用服务器进行会话管理,GAE 不支持(在 1.6.3 中测试)。要解决这个问题,更新 web.xml 文件,定义“javax.faces.STATE_SAVING_METHOD,把值设为“客户端”。

文件:web.xml

 <context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>client</param-value>
	</context-param> 

参考

  1. 用 JavaServer Faces 开发 Web 应用
  2. 使用 JSF 2 和谷歌应用引擎

gae jsf2

Mac OS X 上的 GAE + Python hello world

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/gae-python-hello-world-on-mac-os-x/

在本教程中,我们将向您展示如何在 Mac OS X 上使用 Python 创建一个简单的 GAE hello world web 项目,并通过 Google App Engine Launcher 运行它。

使用的工具:

  1. 用于 Python 的谷歌应用引擎 SDK(Mac OS X)-1 . 7 . 0
  2. 苹果 OS X 10.8
  3. Python 2.7

Note
By default, Mac OS X 10.8, has Python 2.7 installed, which makes Google App Engine development more easier.

1.谷歌应用引擎 SDK

访问这个Google App Engine SDK for Python,选择 Mac OS X 并开始下载。

1.1 安装 Google App Engine SDK
双击下载的GoogleAppEngineLauncher-version.dmg文件,会提取出“ GoogleAppEngineLauncher ”图标,拖到你希望 GAE SDK 安装的文件夹中。

1.2 再次运行 Google App Engine Launcher
,双击“ GoogleAppEngineLauncher ”图标,按照向导提示完成安装。

图:Google appengine launcher–这个 GAE 启动器帮助你运行、部署和管理你的应用程序。

gae launcher example

2.Python Hello World

File:hello . py–创建一个简单的 python 文件来显示 hello world 消息。

 import webapp2

class MainPage(webapp2.RequestHandler):
  def get(self):
      self.response.headers['Content-Type'] = 'text/plain'
      self.response.out.write('Hello World, GAE + Python')

app = webapp2.WSGIApplication([('/', MainPage)], debug=True) 

文件:app . YAML–创建一个简单的 GAE 配置文件。

 application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: hello.app 

完成了。

3.导入、运行和演示

在 GAE 启动程序中,两个手指点击表格网格->选择“添加已有… ”,找到上面包含 Python 文件的文件夹。

gae launcher add existing project

运行它并点击浏览以查看部署的 web 应用程序。

gae launcher

见演示:http://localhost:8888

result

下载源代码

Download it – gae-python-hello-world.zip (3 kb)

参考

  1. GAE 入门:Python 2.7
  2. 在 Mac OS X 10.6 上使用谷歌应用引擎 SDK 和 Python 2.7

在 Spring Security 中获取当前登录的用户名

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-security/get-current-logged-in-username-in-spring-security/

在本文中,我们将向您展示在 Spring Security 中获取当前登录用户名的三种方法。

1.security context holder+authentic ation . getname()

 import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

  @RequestMapping(value="/login", method = RequestMethod.GET)
  public String printUser(ModelMap model) {

      Authentication auth = SecurityContextHolder.getContext().getAuthentication();
      String name = auth.getName(); //get logged in username

      model.addAttribute("username", name);
      return "hello";

  }
  //... 

2.security context holder+user . get username()

 import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

  @RequestMapping(value="/login", method = RequestMethod.GET)
  public String printUser(ModelMap model) {

      User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      String name = user.getUsername(); //get logged in username

      model.addAttribute("username", name);
      return "hello";

  }
  //... 

3.usernamepasswordtauthenticationtoken

这是更优雅的解决方案,在运行时,Spring 会将UsernamePasswordAuthenticationToken注入到Principal接口中。

 import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

  @RequestMapping(value="/login", method = RequestMethod.GET)
  public String printWelcome(ModelMap model, Principal principal ) {

      String name = principal.getName(); //get logged in username
      model.addAttribute("username", name);
      return "hello";

  }
  //... 

下载源代码

Download it – Spring-Security-Get-Logged-In-Username.zip (9 KB)

参考

  1. 安全上下文持有者 JavaDoc
  2. 用户 JavaDoc
  3. usernamepasswordtauthenticationtoken JavaDoc

Tags : spring security

相关文章

使用 Eclipse 的 Google app engine Java hello world 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-hello-world-example-using-eclipse/

在本教程中,我们将向您展示如何使用 Eclipse 创建一个Google App Engine(GAE)Java项目(hello world 示例),在本地运行它,并将其部署到 Google App Engine 帐户。

使用的工具:

  1. JDK 1.6
  2. Eclipse 3.7+Eclipse 的 Google 插件
  3. 谷歌应用引擎 Java SDK 1.6.3.1

Note
GAE supports Java 1.5 and 1.6.

P.S 假设安装了 JDK1.6 和 Eclipse 3.7。

1.为 Eclipse 安装谷歌插件

阅读本指南-如何为 Eclipse 安装谷歌插件。如果你同时安装了 Google App Engine Java SDK 和“ Google Plugin for Eclipse ”,那么转到步骤 2,否则,获取 Google App Engine Java SDK 并解压。

2.创建新的 Web 应用程序项目

在 Eclipse 工具栏中,点击 Google 图标,选择“新建 Web 应用项目…

图-新的 Web 应用项目

Choose new web application project

图–取消选择“ Google Web ToolKit ”,通过“ configure SDK ”链接链接您的 GAE Java SDK。

create new web application project

单击 finished,Google Plugin for Eclipse 将自动生成一个示例项目。

3.你好世界

查看生成的项目目录。

gae project directory

没什么特别的,标准的 Java web 项目结构。

 HelloWorld/
  src/
    ...Java source code...
    META-INF/
      ...other configuration...
  war/
    ...JSPs, images, data files...
    WEB-INF/
      ...app configuration...
      lib/
        ...JARs for libraries...
      classes/
        ...compiled classes... 

额外的是这个文件“appengine-web.xml”,Google App Engine 需要这个来运行和部署应用程序。

文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application></application>
  <version>1</version>

  <!-- Configure java.util.logging -->
  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
  </system-properties>

</appengine-web-app> 

4.在本地运行

右键单击项目并作为“ Web 应用程序”运行。

Eclipse 控制台:

 //...
INFO: The server is running at http://localhost:8888/
30 Mac 2012 11:13:01 PM com.google.appengine.tools.development.DevAppServerImpl start
INFO: The admin console is running at http://localhost:8888/_ah/admin 

访问 URL http://localhost:8888/,参见输出

gae hello world demo

还有 hello world servlet–http://localhost:8888/helloworld

gae hello world demo

5.部署到 Google 应用引擎

https://appengine.google.com/上注册一个帐户,并为您的网络应用程序创建一个应用程序 ID。

在本演示中,我创建了一个名为“mkyong123”的应用程序 ID,并将其放在appengine-web.xml中。

文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong123</application>
  <version>1</version>

  <!-- Configure java.util.logging -->
  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
  </system-properties>

</appengine-web-app> 

要部署,请参见以下步骤:

图 1.1–点击工具栏上的 GAE 部署按钮。

deploy to google app engine

图 1.2–使用您的 Google 帐户登录并点击部署按钮。

deploy to google app engine

图 1.3–如果一切正常,hello world web 应用程序将被部署到这个 URL——http://mkyong123.appspot.com/

deploy to google app engine

完成了。

参考

  1. 谷歌应用引擎——入门:Java
  2. 谷歌应用引擎 Python hello world 使用 Eclipse 的例子

谷歌应用引擎+ JDO + Spring MVC,CRUD 例子

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-jdo-spring-mvc-crud-example/

Note
This tutorial is more on practice guide, please refer to this official Using JDO in datastore for detail explanation.

参见下面的代码片段,使用 Java 数据对象(JDO) 在 GAE 数据存储上执行 CRUD。只需用 JDO 注释对客户进行注释,并通过 PersistenceManager 执行 CRUD。

增加

 Customer c = new Customer();
	c.setName(name);

	PersistenceManager pm = PMF.get().getPersistenceManager();
	try {
		pm.makePersistent(c);
	} finally {
		pm.close();
	} 

搜索

搜索“客户”,其中 name = =“mkyong”。

 PersistenceManager pm = PMF.get().getPersistenceManager();

	Query q = pm.newQuery(Customer.class);
	q.setFilter("name == nameParameter");
	q.setOrdering("date desc");
	q.declareParameters("String nameParameter");

	try {
		List<Customer> results = (List<Customer>) q.execute("mkyong");
		//...
	} finally {
		q.closeAll();
		pm.close();
	} 

搜索“客户”,其中 name = =“mkyong”,email = =“test @ Gmail . com”。

 Query q = pm.newQuery(Customer.class);
	q.setOrdering("date desc");
	q.setFilter("name == nameParameter && email == emailParameter");
	q.declareParameters("String nameParameter, String emailParameter");

	try {
		List<Customer> results = (List<Customer>) q.execute("mkyong", "test@gmail.com");
		//...
	} finally {
		q.closeAll();
		pm.close();
	} 

客户记录返回列表。

 PersistenceManager pm = PMF.get().getPersistenceManager();
	Query q = pm.newQuery(Customer.class);
	q.setOrdering("date desc");
	List<Customer> results = null;

	try {
		results = (List<Customer>) q.execute();
		if (!results.isEmpty()) {
			// good for listing
		}	
	} finally {
		q.closeAll();
		pm.close();
	} 

更新

若要更新,请获取现有对象并修改它。

 PersistenceManager pm = PMF.get().getPersistenceManager();
	try {
		Customer c = pm.getObjectById(Customer.class, key);
		c.setName(name);
		c.setEmail(email);
		c.setDate(new Date());
	} finally {
		pm.close();
	} 

删除

 PersistenceManager pm = PMF.get().getPersistenceManager();
	try {
		Customer c = pm.getObjectById(Customer.class, key);
		pm.deletePersistent(c);
	} finally {
		pm.close();
	} 

GAE + Spring MVC + CRUD 示例

好了,现在我们将向您展示一个使用 Spring MVC 以 REST 风格开发的简单 web 应用程序,它使用 JDO 在 datastore 中存储数据。

  1. 谷歌应用引擎 Java SDK 1.6.3.1,JDO 2.3
  2. 弹簧 3.1.1
  3. JDK 1.6
  4. Eclipse 3.7+Eclipse 的 Google 插件

另外,使用 Google Plugin for Eclipse 创建一个 web 应用程序项目模板,它会自动为您创建和配置jdoconfig.xml

Note
This example is keep into as simple as possible, to show you how to use JDO to perform CRUD only, no layers like DAO or BO, no validation or message notification of the success or failed action.

1.顾客

用 JDO 注释来注释客户对象。

 package com.mkyong.model;

import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;

@PersistenceCapable
public class Customer {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    private String name;

    @Persistent
    private String email;

    @Persistent
    private Date date;

    //getter and setter methods
} 

2.持久性管理器

创建一个 singleton PersistenceManager 类。

 package com.mkyong;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
	private static final PersistenceManagerFactory pmfInstance = JDOHelper
		.getPersistenceManagerFactory("transactions-optional");

	private PMF() {
	}

	public static PersistenceManagerFactory get() {
		return pmfInstance;
	}
} 

3.弹簧控制器

弹簧控制器,REST 风格,执行 CRUD 操作。代码应该是不言自明的。

文件:CustomerController.java

 package com.mkyong.controller;

import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.PMF;
import com.mkyong.model.Customer;

@Controller
@RequestMapping("/customer")
public class CustomerController {

	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public String getAddCustomerPage(ModelMap model) {

		return "add";

	}

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public ModelAndView add(HttpServletRequest request, ModelMap model) {

		String name = request.getParameter("name");
		String email = request.getParameter("email");

		Customer c = new Customer();
		c.setName(name);
		c.setEmail(email);
		c.setDate(new Date());

		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(c);
		} finally {
			pm.close();
		}

		return new ModelAndView("redirect:list");

	}

	@RequestMapping(value = "/update/{name}", method = RequestMethod.GET)
	public String getUpdateCustomerPage(@PathVariable String name,
		HttpServletRequest request, ModelMap model) {

		PersistenceManager pm = PMF.get().getPersistenceManager();

		Query q = pm.newQuery(Customer.class);
		q.setFilter("name == nameParameter");
		q.setOrdering("date desc");
		q.declareParameters("String nameParameter");

		try {
			List<Customer> results = (List<Customer>) q.execute(name);

			if (results.isEmpty()) {
				model.addAttribute("customer", null);
			} else {
				model.addAttribute("customer", results.get(0));
			}
		} finally {
			q.closeAll();
			pm.close();
		}

		return "update";

	}

	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public ModelAndView update(HttpServletRequest request, ModelMap model) {

		String name = request.getParameter("name");
		String email = request.getParameter("email");
		String key = request.getParameter("key");

		PersistenceManager pm = PMF.get().getPersistenceManager();

		try {

			Customer c = pm.getObjectById(Customer.class, key);

			c.setName(name);
			c.setEmail(email);
			c.setDate(new Date());

		} finally {

			pm.close();
		}

		// return to list
		return new ModelAndView("redirect:list");

	}

	@RequestMapping(value = "/delete/{key}", method = RequestMethod.GET)
	public ModelAndView delete(@PathVariable String key,
			HttpServletRequest request, ModelMap model) {

		PersistenceManager pm = PMF.get().getPersistenceManager();

		try {

			Customer c = pm.getObjectById(Customer.class, key);
			pm.deletePersistent(c);

		} finally {
			pm.close();
		}

		// return to list
		return new ModelAndView("redirect:../list");

	}

	// get all customers
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String listCustomer(ModelMap model) {

		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Customer.class);
		q.setOrdering("date desc");

		List<Customer> results = null;

		try {
			results = (List<Customer>) q.execute();

			if (results.isEmpty()) {
				model.addAttribute("customerList", null);
			} else {
				model.addAttribute("customerList", results);
			}

		} finally {
			q.closeAll();
			pm.close();
		}

		return "list";

	}

} 

4.JSP 页面

显示客户并执行添加、更新和删除的 JSP 页面。

文件:list.jsp

 <%@ page import="java.util.List" %>
<%@ page import="com.mkyong.model.Customer" %>
<%@ page import="com.google.appengine.api.datastore.KeyFactory" %>
<html>
<body>
	<h1>GAE + Spring 3 MVC REST + CRUD Example with JDO</h1>

	Function : <a href="add">Add Customer</a>
	<hr />

	<h2>All Customers</h2>
	<table border="1">
		<thead>
			<tr>
				<td>Name</td>
				<td>Email</td>
				<td>Created Date</td>
				<td>Action</td>
			</tr>
		</thead>

		<%

		if(request.getAttribute("customerList")!=null){

			List<Customer> customers = 
                           (List<Customer>)request.getAttribute("customerList");

			if(!customers.isEmpty()){
				 for(Customer c : customers){

		%>
				<tr>
				  <td><%=c.getName() %></td>
				  <td><%=c.getEmail() %></td>
				  <td><%=c.getDate() %></td>
				  <td><a href="update/<%=c.getName()%>">Update</a> | 
                                      <a href="delete/<%=KeyFactory.keyToString(c.getKey()) %>">
                                       Delete</a>
                                  </td>
				</tr>
		<%	

				}

			}

		   }
		%>

        </tr>

	</table>

</body>
</html> 

文件:add.jsp

 <html>
<body>
	<h1>Add Customer</h1>

	<form method="post" action="add">
		<table>
			<tr>
				<td>UserName :</td>
				<td><input type="text" style="width: 185px;" maxlength="30"
					name="name" id="name" /></span></td>
			</tr>
			<tr>
				<td>Email :</td>
				<td><input type="text" style="width: 185px;" maxlength="30"
					name="email" id="email" /></span></td>
			</tr>
		</table>
		<input type="submit" class="save" title="Save" value="Save" />
	</form>

</body>
</html> 

文件:update.jsp

 <%@ page import="com.mkyong.model.Customer" %>
<%@ page import="com.google.appengine.api.datastore.KeyFactory" %>
<html>
<body>
	<h1>Update Customer</h1>

	<%
		Customer customer = new Customer();

		if(request.getAttribute("customer")!=null){

			customer = (Customer)request.getAttribute("customer");

		}

	%>

	<form method="post" action="../update" >
		<input type="hidden" name="key" id="key" 
			value="<%=KeyFactory.keyToString(customer.getKey()) %>" /> 

		<table>
			<tr>
				<td>
					UserName :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                             maxlength="30" name="name" id="name" 
						value="<%=customer.getName() %>" />
				</td>
			</tr>
			<tr>
				<td>
					Email :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                             maxlength="30" name="email" id="email" 
						value="<%=customer.getEmail() %>" />
				</td>
			</tr>
		</table>
		<input type="submit" class="update" title="Update" value="Update" />
	</form>

</body>
</html> 

5.演示

完成,看 demo 向你展示 web 应用的工作流程。

1.列表页面,显示现有客户列表。

网址:http://localhost:8888/customer/list

gar jdo example

2.在列表页面中,点击“添加客户”链接,显示添加客户页面,填写新客户,姓名= " mkyong ",邮箱= "【test@yahoo.com】",点击“添加”按钮。

网址:http://localhost:8888/customer/add

gar jdo example

3.保存了客户,就会返回到列表页面。

网址:http://localhost:8888/customer/list

gar jdo example

4.尝试更新链接,它将显示所选客户的数据,更新电子邮件至“mkyong@yahoo.com”,并点击更新按钮。

网址:http://localhost:8888/customer/update/mkyong

gar jdo example

5.电子邮件被更新,并重定向回列表页面。

网址:http://localhost:8888/customer/list

gar jdo example

6.要删除客户,只需点击“删除”链接。

下载源代码

由于文件很大,所有 Spring MVC 和 GAE jar 都被排除在外。

Download – GAE-SpringMVC-JDO-example.zip (22 KB)

参考

  1. Java 数据对象(JDO)
  2. GAE:利用 JDO
  3. GAE:数据存储低层 api
  4. GAE:JDO 和 Spring MVC 的 CRUD 操作

crud gae jdo spring mvc

谷歌应用引擎+ JSF 2 的例子

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-jsf-2-example/

在本教程中,我们将向您展示如何在谷歌应用引擎(GAE)环境中开发和部署 JSF 2.0 web 应用程序。

使用的工具和技术:

  1. JDK 1.6
  2. Eclipse 3.7+Eclipse 的 Google 插件
  3. 谷歌应用引擎 Java SDK 1.6.3.1
  4. JSF 2.1.7

Note
This example is going to reuse this JSF 2.0 hello world example, modify it and merge it with this GAE + Java example.

1.新建 Web 应用程序项目

在 Eclipse 中,创建一个新的 Web 应用项目,命名为“ JSFGoogleAppEngine ”。

generate a new web application GAE project

“谷歌 Eclipse 插件”将生成一个 GAE 项目结构的样本。

2.JSF 新协议的附属协议

要在 GAE 使用 JSF 2,你需要以下罐子

  1. jsf-api-2.1.7.jar
  2. jsf-impl-2.1.7.jar
  3. 埃尔里-1.0.jar

复制后放入“ war/WEB-INF/lib ”文件夹。

gae jsf2 dependency libraries

右击项目文件夹,选择“属性”。选择“ Java 构建路径->-”选项卡,点击“添加 Jars 按钮,选择上面的 Jars。

gae jsf2 java build pathNote
You need to put this el-ri-1.0.jar, otherwise, you will hit error message – Unable to instantiate ExpressionFactory ‘com.sun.el.ExpressionFactoryImpl’.

3.JSF 管理比恩

3.1 删除插件生成的JSFGoogleAppEngineServlet.java,不需要这个。

3.2 创建一个受管理的 bean。

文件:src/com/mkyong/hello bean . Java

 package com.mkyong;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import java.io.Serializable;

@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

} 

3.3 创建一个新的 WebConfiguration.java。

JSF 2 号正在使用“javax.naming.InitialContext”这在 GAE 是不支持的。

要解决这个问题,你需要得到一份 JSF 的源代码,克隆出WebConfiguration.java,注释正在使用javax.naming.InitialContext类的方法,把它放在src/com/sun/faces/com fig/web configuration . Java。现在,您新创建的WebConfiguration.java类将重载原来的WebConfiguration.java

Note
Get the full source code of the WebConfiguration.java.

我不认为 GAE 团队会白名单这个罐子,只是希望 JSF 的团队可以在未来的版本中修复这个问题。

4.JSF 页面

4.1 创建hello.xhtml页面,接受用户输入并将其传递给 helloBean。

文件:war/hello.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>GAE + JSF</title>
</h:head>
<h:body>
	<h1>Google App Engine + JSF 2.0 example - hello.xhtml</h1>
	<h:form>
		<h:inputText value="#{helloBean.name}"></h:inputText>
		<h:commandButton value="Welcome Me" action="welcome"></h:commandButton>
	</h:form>
</h:body>
</html> 

4.2 创建welcome.xhtml页面,显示来自 hellobean 的用户输入。

文件:war/welcome.xhtml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>GAE + JSF</title>
</h:head>
<h:body bgcolor="white">
	<h1>Google App Engine + JSF 2.0 example - welcome.xhtml</h1>
	<h2>Welcome #{helloBean.name}</h2>
</h:body>
</html> 

4.3 删除插件生成的index.html文件,你不需要这个。

5.web.xml

更新 web.xml,集成 JSF 2。

文件:web.xml

 <?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>JavaServerFaces</display-name>

	<!-- GAE 1.6.3 cannot handle server side (JSF default) state management. -->
	<context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>client</param-value>
	</context-param>

	<!-- Change to "Production" when you are ready to deploy -->
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<!-- Welcome page -->
	<welcome-file-list>
		<welcome-file>faces/hello.xhtml</welcome-file>
	</welcome-file-list>

	<!-- JSF mapping -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map these files with JSF -->
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

</web-app> 

Note
GAE do not support server side state management, so, you need to define “javax.faces.STATE_SAVING_METHOD” to “client“, to avoid of this “View /hello.xhtml could not be restored” error message in GAE production environment.

6.在 GAE 启用会话

更新appengine-web.xml,启用会话支持,JSF 需要这个。
文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application></application>
  <version>1</version>

	<sessions-enabled>true</sessions-enabled>

</appengine-web-app> 

7.目录结构

审查最终目录结构。

final directory structure

8.在本地运行

右键单击项目,作为“Web 应用程序”运行。

网址:http://localhost:8888/hello . JSF

local output

点击按钮。

local output

10.部署在 GAE

更新appengine-web.xml文件,添加您的 App Engine 应用 ID。

文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong-jsf2gae</application>
  <version>1</version>

	<sessions-enabled>true</sessions-enabled>

</appengine-web-app> 

选择项目,点击谷歌图标,“部署到应用引擎”。

deploy on GAE

网址:http://mkyong-jsf2gae.appspot.com/hello.jsf

gae production output

下载源代码

由于文件很大,所有 JSF 和 GAE 的罐子都被排除在外。

Download – JSF2-GoogleAppEngine-Example.zip (42 KB)

参考

  1. JSF 和 GAE 兼容问题
  2. 谷歌应用上的 JSF 2 配置
  3. 带 JSF 2 + CDI 的谷歌应用引擎
  4. 开始使用谷歌应用和 JSF
  5. JSF 2.0 hello world 示例
  6. Oracle : JavaServer Faces 开发教程

Tags : gae jsf2

相关文章

使用 Eclipse 的 Google app engine Python hello world 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-python-hello-world-example-using-eclipse/

在本教程中,我们将向您展示如何使用 Eclipse 创建一个Google App Engine(GAE)Pythonweb 项目(hello world 示例),在本地运行它,并将其部署到 Google App Engine 帐户。

使用的工具:

  1. Python 2.7
  2. Eclipse 3.7 + PyDev 插件
  3. 用于 Python 1.6.4 的谷歌应用引擎 SDK

P.S 假设安装了 Python 2.7 和 Eclipse 3.7。

1.为 Eclipse 安装 PyDev 插件

使用下面的 URL 安装 PyDev 作为 Eclipse 插件

 http://pydev.org/updates 

图 1——在 Eclipse 菜单中,“帮助—>安装新软件。”并放在上面的网址。选择“ PyDev for Eclipse ”选项,按照步骤操作,并在完成后重启 Eclipse。

pydev eclipse

2.验证 PyDev

Eclipse 重启后,确保 PyDev 的解释器指向你的python.exe

图 2-Eclipse->-Windows->首选项,确保“解释器-Python配置正确。

pydev eclipse config

3.谷歌应用引擎 SDK Python

下载并安装Google App Engine SDK for Python

4.Eclipse 中的 Python Hello World

下面的步骤向你展示了如何通过 Pydev 插件创建一个 GAE 项目。

图 4.1–Eclipse 菜单,文件- >新建- >其他…,PyDev 文件夹,选择“ PyDev Google App Engine 项目”。

gae python hello world example

图 4.2–键入项目名称,如果解释器尚未配置(在步骤 2 中),您现在可以这样做。并选择此选项—“创建‘src’文件夹并将其添加到 PYTHONPATH ”。

gae python hello world example

图 4.3–点击“浏览”按钮,指向 Google App Engine 安装目录(在步骤 3 中)。

gae python hello world example

图 4.4–在 GAE 命名您的应用程序 id,键入任何内容,您可以稍后更改。并选择“ Hello Webapp World 模板生成示例文件。

gae python hello world example

图 4.5–完成,生成 4 个文件,.pydevproject.project都是 Eclipse 项目文件,忽略。

gae python hello world example

查看生成的 Python 文件:

File:helloworld . py——只输出一个 hello world。

 from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class MainPage(webapp.RequestHandler):

    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Hello, webapp World!')

application = webapp.WSGIApplication([('/', MainPage)], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main() 

文件:app . YAML–GAE 需要这个文件来运行和部署你的 Python 项目,它非常简单明了,详细的语法和配置,请访问 yamlapp.yaml 参考

 application: mkyong-python
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: helloworld.py 

5.在本地运行

要在本地运行它,右击helloworld.py,选择“运行方式”—>“运行配置”,创建一个新的“ PyDev Google App 运行”。

图 5.1-在主选项卡- >主模块中,手动键入“ dev_appserver.py 的目录路径。“浏览”按钮不能够帮助你,手动输入。

gea python run locally

图 5.2–在“参数”选项卡- >程序参数中,填入“ ${project_loc}/src ”。

gea python run locally

图 5.3–运行它。默认情况下,它会部署到 http://localhost:8080

gea python run locally

图 5.4–完成。

gea python run locally

5.部署到 Google 应用引擎

https://appengine.google.com/上注册一个账户,并为你的网络应用创建一个应用 ID。再次回顾“app.yaml”,这个 web 应用程序将被部署到 GAE,应用程序 ID 为“ mkyong-python ”。

文件:app.yaml

 application: mkyong-python
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: helloworld.py 

要部署到 GAE,请参见以下步骤:

图 5.1-新建一个“PyDev Google App Run”,在主选项卡- >主模块中,手动键入“ appcfg.py 的目录路径。

deploy python to GAE

图 5.2–在参数选项卡- >程序参数中,放入“更新${project_loc}/src ”。

deploy python to GAE

图 5.3–在部署过程中,您需要输入您的 GAE 电子邮件和密码进行验证。

deploy python to GAE

图 5.4-如果成功,web app 将部署到 http://mkyong-python.appspot.com/

*deploy python to GAE

完成了。

参考

  1. 用于 Eclipse 的 PyDev 插件
  2. Yaml 官网
  3. GAE 开始使用 Python
  4. 为 Eclipse 安装 PyDev】
  5. GAE Java hello world 使用 Eclipse 的例子

*

Google App Engine + Spring 3 MVC REST 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-spring-3-mvc-rest-example/

在本教程中,我们将向您展示如何在 Google App Engine()环境中开发和部署一个 Spring 3.0 MVC REST web 应用程序。

**使用的工具和技术:

  1. 谷歌应用引擎 Java SDK 1.6.3.1
  2. 弹簧 3.1.1
  3. JDK 1.6
  4. Eclipse 3.7+Eclipse 的 Google 插件

Note
This example is going to reuse this Spring 3 MVC REST example, modify it and integrate with Google App Engine, you may also interest to read this – GAE + Java + Eclipse example

1.新建 Web 应用程序项目

在 Eclipse 中,创建一个新的 Web 应用项目,命名为“ SpringMVCGoogleAppEngine ”。

gae spring new web application

Eclipse 的“ Google 插件将生成一个 GAE 项目结构的样本。

2.Spring 3.0 依赖项

要在 GAE 使用 Spring MVC + REST ,您需要以下 jar

  1. aopalliance-1.0.jar
  2. commons-logging-1.1.1.jar
  3. spring-aop-3.1.1
  4. spring-asm-3.1.1 .版本. jar
  5. spring-beans-3.1.1.RELEASE.jar
  6. spring 上下文 3.1.1.RELEASE.jar
  7. spring-context-support-3.1.1
  8. 3.1.1.RELEASE.jar
  9. spring-表达式-3.1.1.RELEASE.jar
  10. spring-web-3.1.1.RELEASE.jar
  11. spring-webmvc-3.1.1

复制后放入“ war/WEB-INF/lib ”文件夹。

gae spring dependency library

将其添加到项目的构建路径中——右键单击项目文件夹,选择“ Properties ”。选择“ Java 构建路径->-”选项卡,点击“添加 Jars 按钮,选择上面的 Jars。

gae spring java build path ## 3.弹簧控制器

3.1 删除自动生成的SpringMVCGoogleAppEngineServlet.java,不需要这个。

3.2 创建一个 bean,在 REST 结构中充当控制器。此外,阿迪的消息进入了“message”属性。

文件:src/com/mkyong/movie controller . Java

 package com.mkyong.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/movie")
public class MovieController {

	//DI via Spring
	String message;

	@RequestMapping(value="/{name}", method = RequestMethod.GET)
	public String getMovie(@PathVariable String name, ModelMap model) {

		model.addAttribute("movie", name);
		model.addAttribute("message", this.message);

		//return to jsp page, configured in mvc-dispatcher-servlet.xml, view resolver
		return "list";

	}

	public void setMessage(String message) {
		this.message = message;
	}

} 

4.JSP 页面

创建一个list.jsp页面,显示结果。

文件:war/list.jsp

 <html>
<body>
	<h1>GAE + Spring 3 MVC REST example</h1>

	<h2>Movie : ${movie} , DI message : ${message}</h2>	
</body>
</html> 

5.弹簧配置

创建一个 Spring XML bean 配置文件,定义 bean 并查看解析器。

文件:war/we b-INF/MVC-dispatcher-servlet . XML

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

	<!-- 
		Need DI a message into controller, so auto component scan is disabled, 
		to avoid double create the movieController bean.
                Only controller need this hack.
	-->
	<context:component-scan base-package="com.mkyong.controller">
		<context:exclude-filter type="regex"
			expression="com.mkyong.controller.Movie.*" />
	</context:component-scan>

	<mvc:annotation-driven />

	<!-- Bean to show you Di in GAE, via Spring, also init the MovieController -->
	<bean class="com.mkyong.controller.MovieController">
		<property name="message">
			<value>Hello World</value>
		</property>
	</bean>

	<bean
	   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

</beans> 

6.web.xml

更新web.xml,集成 Spring 框架。

文件:war/WEB-INF/web.xml

 <?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>
                    org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
                    org.springframework.web.context.ContextLoaderListener
                </listener-class>
	</listener>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app> 

7.目录结构

查看最终的目录结构。

gae spring final directory structure

8.在本地运行

右键点击项目,运行为“ Web 应用”。

网址:http://localhost:8888/movie/Avengers

gae spring deploy on local development environemnt

9.部署在 GAE

更新appengine-web.xml文件,添加您的 App Engine 应用 ID。

文件:war/we b-INF/app engine-WEB . XML

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong-springmvc</application>
  <version>1</version>

  <system-properties>
    <property name="java.util.logging.config.file" 
          value="WEB-INF/logging.properties"/>
  </system-properties>

</appengine-web-app> 

选择项目,点击谷歌图标,“部署到应用引擎”。

网址:http://mkyong-springmvc.appspot.com/movie/forrest gump

gae spring deploy on production environment

下载源代码

由于文件较大,所有 Spring 和 GAE jar 都被排除在外。

Download – SpringMVC-GoogleAppEngine.zip (12 KB)

参考

  1. 春天 3.0 豆子参考
  2. REST 解释维基百科
  3. Google App Engine+Java+Google Plugin for eclipse 示例
  4. Spring 3 MVC hello world 示例
  5. 春天 3 休息你好世界示例
  6. Google 添加引擎 Java doc

gae rest spring mvc spring rest

Google App Engine + Spring MVC,带有数据存储低级 api 的 CRUD 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-spring-mvc-crud-example-with-datastore-low-level-api/

GAE datastore
Refer to this official “Using datstore guide” to understand what is GAE datastore.

参见以下代码片段,使用低级 API 为 Google App Engine datastore,Java 执行 CRUD。

增加

将客户存储到数据存储中,以“name”作为键。

 Key customerKey = KeyFactory.createKey("Customer", "your name");
    Entity customer = new Entity("Customer", customerKey);
    customer.setProperty("name", "your name");
    customer.setProperty("email", "your email");

    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    datastore.put(customer); //save it 

搜索

返回 10 个客户作为列表。

 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	Query query = new Query("Customer").addSort("date", Query.SortDirection.DESCENDING);
	List<Entity> customers = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10)); 

用匹配的过滤器找到并返回一个客户。

 Query query = new Query("Customer");
	query.addFilter("name", FilterOperator.EQUAL, "your name");
	PreparedQuery pq = datastore.prepare(query);
	Entity customer = pq.asSingleEntity(); 

FilterOperator.EQUAL
Play this filters, it has few condition options, like less than, great than and etc.

更新

要更新,只需修改现有实体并再次保存即可。

 Query query = new Query("Customer");
	query.addFilter("name", FilterOperator.EQUAL, "your name");
	PreparedQuery pq = datastore.prepare(query);
	Entity customer = pq.asSingleEntity();

	customer.setProperty("name", name);
	customer.setProperty("email", email);

	DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        datastore.put(customer); //GAE will know save or update 

删除

要删除,需要实体键。

 Query query = new Query("Customer");
    query.addFilter("name", FilterOperator.EQUAL, name);
    PreparedQuery pq = datastore.prepare(query);
    Entity customer = pq.asSingleEntity();

    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    datastore.delete(customer.getKey()); //delete it 

GAE + Spring MVC + CRUD 示例

好了,现在我们将向您展示一个使用 Spring MVC 以 REST 风格开发的简单 web 应用程序,操作 Google App Engine datastore 中的数据,使用上面的低级 API。

  1. 谷歌应用引擎 Java SDK 1.6.3.1
  2. 弹簧 3.1.1
  3. JDK 1.6
  4. Eclipse 3.7+Eclipse 的 Google 插件

Note
This example is keep into as simple as possible, to show you how to perform CRUD only, no layers like DAO or BO, no validation or message notification of the success or failed action.

1.弹簧控制器

Spring 控制器,REST 风格,用于显示网页和执行 CRUD。代码应该是不言自明的。

文件:CustomerController.java

 package com.mkyong.controller;

import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;

@Controller
@RequestMapping("/customer")
public class CustomerController {

	@RequestMapping(value="/addCustomerPage", method = RequestMethod.GET)
	public String getAddCustomerPage(ModelMap model) {

		return "add";

	}

	@RequestMapping(value="/add", method = RequestMethod.POST)
	public ModelAndView add(HttpServletRequest request, ModelMap model) {

		String name = request.getParameter("name");
		String email = request.getParameter("email");

	        Key customerKey = KeyFactory.createKey("Customer", name);

		Date date = new Date();
                Entity customer = new Entity("Customer", customerKey);
                customer.setProperty("name", name);
                customer.setProperty("email", email);
                customer.setProperty("date", date);

                DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
                datastore.put(customer);

                return new ModelAndView("redirect:list");

	}

	@RequestMapping(value="/update/{name}", method = RequestMethod.GET)
	public String getUpdateCustomerPage(@PathVariable String name, 
			HttpServletRequest request, ModelMap model) {

		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("Customer");
		query.addFilter("name", FilterOperator.EQUAL, name);
		PreparedQuery pq = datastore.prepare(query);

		Entity e = pq.asSingleEntity();
		model.addAttribute("customer",  e);

		return "update";

	}

	@RequestMapping(value="/update", method = RequestMethod.POST)
	public ModelAndView update(HttpServletRequest request, ModelMap model) {

		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

		String name = request.getParameter("name");
		String email = request.getParameter("email");
		String originalName =  request.getParameter("originalName");

		Query query = new Query("Customer");
		query.addFilter("name", FilterOperator.EQUAL, originalName);
		PreparedQuery pq = datastore.prepare(query);
		Entity customer = pq.asSingleEntity();

		customer.setProperty("name", name);
		customer.setProperty("email", email);
		customer.setProperty("date", new Date());

                datastore.put(customer);

               //return to list
               return new ModelAndView("redirect:list");

	}

	@RequestMapping(value="/delete/{name}", method = RequestMethod.GET)
	public ModelAndView delete(@PathVariable String name,
			HttpServletRequest request, ModelMap model) {

                DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

                Query query = new Query("Customer");
		query.addFilter("name", FilterOperator.EQUAL, name);
		PreparedQuery pq = datastore.prepare(query);
		Entity customer = pq.asSingleEntity();

                datastore.delete(customer.getKey());

                //return to list
                return new ModelAndView("redirect:../list");

	}

	//get all customers
	@RequestMapping(value="/list", method = RequestMethod.GET)
	public String listCustomer(ModelMap model) {

		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = 
                      new Query("Customer").addSort("date", Query.SortDirection.DESCENDING);
	        List<Entity> customers = 
                      datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));

	        model.addAttribute("customerList",  customers);

		return "list";

	}

} 

2.JSP 页面

3 个 JSP 页面来显示客户并执行添加和更新。

文件:list.jsp

 <%@ page import="java.util.List" %>
<%@ page import="com.google.appengine.api.datastore.Entity" %>
<html>
<body>
	<h1>GAE + Spring 3 MVC REST + CRUD Example</h1>

	Function : <a href="addCustomerPage">Add Customer</a>
	<hr />

	<h2>All Customers</h2>
	<table border="1">
		<thead>
			<tr>
				<td>Name</td>
				<td>Email</td>
				<td>Created Date</td>
				<td>Action</td>
			</tr>
		</thead>
		<%

		    List<Entity> customers = (List<Entity>)request.getAttribute("customerList");
		    for(Entity e : customers){

		%>
			<tr>
			  <td><%=e.getProperty("name") %></td>
			  <td><%=e.getProperty("email") %></td>
			  <td><%=e.getProperty("date") %></td>
			  <td><a href="update/<%=e.getProperty("name")%>">Update</a> 
                             | <a href="delete/<%=e.getProperty("name")%>">Delete</a></td>
			</tr>
		<%
			}
		%>
	</table>

</body>
</html> 

文件:add.jsp

 <html>
<body>
	<h1>Add Customer</h1>

	<form method="post" action="add" >
		<table>
			<tr>
				<td>
					UserName :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                              maxlength="30" name="name" id="name" />
				</td>
			</tr>
			<tr>
				<td>
					Email :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                            maxlength="30" name="email" id="email" />
				</td>
			</tr>
		</table>
		<input type="submit" class="save" title="Save" value="Save" />
	</form>

</body>
</html> 

文件:update.jsp

 <%@ page import="com.google.appengine.api.datastore.Entity" %>
<html>
<body>
	<h1>Update Customer</h1>

	<%
		Entity customer = (Entity)request.getAttribute("customer");
	%>

	<form method="post" action="../update" >
		<input type="hidden" name="originalName" id="originalName" 
			value="<%=customer.getProperty("name") %>" /> 

		<table>
			<tr>
				<td>
					UserName :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                             maxlength="30" name="name" id="name" 
						value="<%=customer.getProperty("name") %>" />
				</td>
			</tr>
			<tr>
				<td>
					Email :
				</td>
				<td>
					<input type="text" style="width: 185px;" 
                                            maxlength="30" name="email" id="email" 
						value="<%=customer.getProperty("email") %>" />
				</td>
			</tr>
		</table>
		<input type="submit" class="update" title="Update" value="Update" />
	</form>

</body>
</html> 

3.弹簧配置

扫描 Spring 控制器并配置视图解析器,以便它可以将视图重定向到 jsp 页面。

文件:mvc-dispatcher-servlet.xml

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

	<context:component-scan base-package="com.mkyong.controller" />
	<mvc:annotation-driven />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

</beans> 

4.集成弹簧

将 Spring 集成到 web 应用程序中。

文件:web.xml

 <?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>
                      org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
                   org.springframework.web.context.ContextLoaderListener
                </listener-class>
	</listener>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app> 

5.演示

完成,看 demo,向你展示 web 应用的工作流程。

1.列表页面,显示现有客户列表。

网址:http://localhost:8888/customer/list

gae spring mvc crud example - list

2.在列表页面中,点击“添加客户”链接以显示添加客户页面,填写新客户,并点击“添加”按钮。

URL : http://localhost:8888/customer/addCustomerPage

gae spring mvc crud example - add

3.保存了客户后,它会返回到列表页面。

网址:http://localhost:8888/customer/list

gae spring mvc crud example - list

4.尝试更新链接,它将显示所选客户的数据,更新电子邮件地址并点击更新按钮。

网址:http://localhost:8888/customer/update/mkyong

gae spring mvc crud example - update

5.电子邮件被更新,并重定向回列表页面。

网址:http://localhost:8888/customer/list

gae spring mvc crud example - list

6.要删除客户,只需点击“删除”链接。

下载源代码

由于文件很大,所有 Spring MVC 和 GAE jar 都被排除在外。

Download – GoogleAppEngine-SpringMVC-datastore.zip (17 KB)

参考

  1. GAE:使用数据存储
  2. GAE:实体
  3. GAE:数据存储低层 api
  4. GAE:JDO 和 Spring MVC 的 CRUD 操作
  5. 使用 Google App Engine、Spring MVC 和 Flex 的体验

Google 应用引擎+ Struts 1 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-struts-1-example/

经典 Struts 1 框架万岁,在本教程中,我们将向您展示如何在 Google App Engine (GAE)环境下开发一个 Struts 1.x web 应用。

使用的工具和技术:

  1. JDK 1.6
  2. Eclipse 3.7+Eclipse 的 Google 插件
  3. 谷歌应用引擎 Java SDK 1.6.3.1
  4. Struts 1.3.10

Note
You may also interest at this Google App Engine + Struts 2 example.

这个例子将把 Struts 1.x hello world 例子与这个 GAE + Java 例子合并。

1.新建 Web 应用程序项目

在 Eclipse 中,创建一个新的 Web 应用程序项目,命名为“StrutsGoogleAppEngine”。

struts1 on gae example

Google Plugin for Eclipse 将生成一个样本 GAE 项目结构。稍后将把 Struts 1 集成到这个 GAE 结构中。

2.集成 Struts 1.x 库

访问此链接下载 Struts 1.x 。需要以下罐子:

  • antlr-2.7.2.jar
  • commons-beanutils-1.8.0.jar
  • 公共链 1.2.jar
  • 1.8.jar
  • commons-logging-1.0.4.jar
  • 公共验证器 1.3.1.jar
  • 奥罗-2.0.8.jar
  • struts-core-1.3.10.jar
  • struts-taglib-1.3.10.jar

复制后放入“ war/WEB-INF/lib ”文件夹。

struts1 on gae example library

右击项目文件夹,选择属性。选择" Java 构建路径 " - > " "选项卡,点击"添加 Jars "按钮,从" war/WEB-INF/lib "文件夹中选择上面 9 个 Jars 进入构建路径。

struts1 on gae example java build ## 3.集成 Struts 1.x 动作和表单

3.1 删除StrutsGoogleAppEngineServlet.java,你不需要这个。

3.2 创建新的操作类。

文件:src/com/mkyong/action/hello world action . Java

 package com.mkyong.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.mkyong.form.HelloWorldForm;

public class HelloWorldAction extends Action {

	public ActionForward execute(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response)
		throws Exception {

		HelloWorldForm helloWorldForm = (HelloWorldForm) form;
		helloWorldForm.setMessage("Hello World!");

		return mapping.findForward("success");
	}

} 

3.3 创建一个新的表单类。

文件:src/com/mkyong/form/hello world form . Java

 package com.mkyong.form;

import org.apache.struts.action.ActionForm;

public class HelloWorldForm extends ActionForm {

	String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

} 

4.集成 Struts 1.x JSP 页面

4.1 创建HelloWorld.jsp页面,放入“war/User/pages/hello world . JSP”。

文件:HelloWorld.jsp

 <%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>

<html>
<head>
</head>
<body>
	<h1>
	   Google App Engine + Struts 1.x example
	</h1>
	<h2><bean:write name="helloWorldForm" property="message" /></h2>
</body>
</html> 

5.Struts XML 配置

创建一个struts-config.xml文件,放在“war/we b-INF/struts-config . XML”中。

文件:struts-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC 
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" 
"http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">

<struts-config>

	<form-beans>
	   <form-bean name="helloWorldForm" type="com.mkyong.form.HelloWorldForm" />
	</form-beans>

	<action-mappings>
	   <action path="/helloWorld" type="com.mkyong.action.HelloWorldAction"
		name="helloWorldForm">
		<forward name="success" path="/HelloWorld.jsp" />

	   </action>
	</action-mappings>

</struts-config> 

6.web.xml

更新web.xml,整合 Struts。

文件:web.xml

 <?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
		<init-param>
		    <param-name>config</param-name>
		    <param-value>
         		/WEB-INF/struts-config.xml
        	    </param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app> 

7.在 GAE 启用会话

更新appengine-web.xml,启用会话支持,Struts 需要这个。

文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application></application>
  <version>1</version>

	<sessions-enabled>true</sessions-enabled>

</appengine-web-app> 

Note
If you don’t enable session in GAE, you will hit error “java.lang.RuntimeException: Session support is not enabled in appengine-web.xml“.

8.目录结构

查看最终的目录结构。

struts1 on gae example final directory structure

9.在本地运行

右键点击项目,运行为“ Web 应用”。

网址:http://localhost:8888/hello world . do

struts1 on gae example run on local

10.部署在 GAE

更新appengine-web.xml文件,添加您的 App Engine 应用 ID。

文件:appengine-web.xml

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong-strutsgae</application>
  <version>1</version>

  <sessions-enabled>true</sessions-enabled>

</appengine-web-app> 

选择项目,点击谷歌图标,“部署到应用引擎”。

网址:http://mkyong-strutsgae.appspot.com/helloWorld.do

struts1 on gae example deploy on gaeNote
Not much problem, just follow GAE directory structure, at least integrate Struts 1 is more easily than Struts 2.

下载源代码

由于文件较大,所有 Struts1 jars 都被排除在外,需要手动下载。

Download – StrutsGoogleAppEngine (13 KB)

参考

  1. Struts hello world 示例
  2. Google App Engine+Java hello world 示例,使用 Eclipse
  3. 下载 Struts 1.x

gae struts

Google 应用引擎+ Struts 2 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/google-app-engine/google-app-engine-struts-2-example/

在本教程中,我们将向您展示如何在 Google App Engine (GAE)环境下开发 Struts 2 web 应用程序。

使用的工具和技术:

  1. JDK 1.6
  2. Eclipse 3.7+Eclipse 的 Google 插件
  3. 谷歌应用引擎 Java SDK 1.6.3.1
  4. struts 2.3.1.2

Note
Before proceed on this tutorial, make sure you read this – GAE + Java example and Struts 2 hello world example.

1.新建 Web 应用程序项目

在 Eclipse 中,创建一个新的 Web 应用程序项目,命名为“Struts2GoogleAppEngine”。

gae struts2 example new project

Eclipse 的谷歌插件将生成一个 GAE 项目结构的样本。稍后,我们将向您展示如何将 Struts2 与这个生成的 GAE 项目集成。

gae struts2 example sample project ## 2.集成 Struts 2 库

获取以下 Struts 2 依赖库,在此下载 Struts 2

  • asm-3.3.jar
  • asm-commons-3.3
  • 组件树 3.3.jar
  • 文件上传-1.2.2.jar
  • commons-io-2.0.1.jar
  • 2.5.jar
  • 自由标记-2.3.18.jar
  • javassist-3.11.0.GA.jar
  • ognl-3.0.4.jar
  • 支柱 2-核心-2.3.1.2.jar
  • xwork-core-2.3.1.2.jar

全部放入“ war/WEB-INF/lib ”文件夹。

gae struts2 example libraries

右键点击项目文件夹,选择"属性 " - > " Java 构建路径 " - > " "选项卡,点击"添加 Jars 按钮,从" war/WEB-INF/lib "文件夹中选择以上 11 个 Jars 进入构建路径。

gae struts2 example java build path ## 3.集成 Struts 2 代码

3.1 删除生成的Struts2GoogleAppEngineServlet.java,不需要这个。

3.2 创建一个新的 Struts 2 操作类。

文件:src/com/mkyong/user/action/welcome user action . Java

 package com.mkyong.user.action;

public class WelcomeUserAction {

	private String username;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String execute() {

		return "SUCCESS";

	}
} 

3.3 创建一个监听器类,并将 ognl 安全设置为空。

Note
Struts 2 need this listener to run in GAE environment. Read this – Issues when deploying Struts 2 on GAE and Error: result ‘null’ not found

文件:src/com/mkyong/listener/struts 2 listenerongae . Java

 package com.mkyong.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import ognl.OgnlRuntime;

public class Struts2ListenerOnGAE implements ServletContextListener,
		HttpSessionListener, HttpSessionAttributeListener {

	public void contextInitialized(ServletContextEvent sce) {
		OgnlRuntime.setSecurityManager(null);
	}

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void sessionCreated(HttpSessionEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void sessionDestroyed(HttpSessionEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void attributeAdded(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub

	}

} 

3.4 要在本地 GAE 环境中运行 Struts2 项目,必须创建一个TextBlock类,并重载原来的TextBlok类,否则会出现“javax.swing.tree.TreeNode is a restricted class错误信息。希望 Struts2 团队可以在未来的版本中解决这个问题。

TextBlock Source Code
Go this URL to download TextBlock source code.

3.5 审查项目目录结构。

gae struts2 example directory

4.集成 Struts 2 页

4.1 创建一个login.jsp页面,接受用户输入。

文件:war/User/pages/login.jsp

 <%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head></head>
<body>
<h1>GAE + Struts 2 Example</h1>

<s:form action="Welcome">
	<s:textfield name="username" label="Username"/>
	<s:password name="password" label="Password"/>
	<s:submit/>
</s:form>

</body>
</html> 

4.2 创建一个welcome_user.jsp页面。

文件:war/User/pages/welcome _ User . JSP

 <%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head></head>
<body>
<h1>GAE + Struts 2 Example</h1>

<h2>Hello <s:property value="username"/></h2>

</body>
</html> 

4.3 再次审查项目目录结构。

gae struts2 example directory

5.Struts XML 配置

创建一个struts.xml文件,放入“ src/struts.xml ”。

文件:struts.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

  <package name="user" namespace="/User" extends="struts-default">
	<action name="Login">
		<result>pages/login.jsp</result>
	</action>
	<action name="Welcome" class="com.mkyong.user.action.WelcomeUserAction">
		<result name="SUCCESS">pages/welcome_user.jsp</result>
	</action>
   </package>

</struts> 

6.web.xml

更新web.xml,集成 Struts2,配置 ognl 安全监听器。

文件:web.xml

 <?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<filter>
	    <filter-name>struts2</filter-name>
	    <filter-class>
		org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
	    </filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<listener>
		<listener-class>
                   com.mkyong.listener.Struts2ListenerOnGAE
                </listener-class>
	</listener>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app> 

7.目录结构

查看最终的目录结构。

gae struts2 example final directory

8.在本地运行

完成,是时候进行测试了。右键点击项目,运行为“ Web 应用”。

网址:http://localhost:8888/User/log in . action

gae struts2 example run on localgae struts2 example run on local

9.部署在 GAE

更新appengine-web.xml,放上你的 App Engine 应用 ID。

 <?xml version="1.0" encoding="utf-8"?>
<appengine-web-app >
  <application>mkyong-struts2gae</application>
  <version>1</version>

  <!-- Configure java.util.logging -->
  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
  </system-properties>

</appengine-web-app> 

选择项目,点击谷歌图标,“部署到应用引擎”。谷歌 Eclipse 插件将自动部署所有必要的文件到 GAE 生产。

gae struts2 example deploy to GAE

在部署期间,Eclipse 控制台视图中将显示以下类似的消息。

 ------------ Deploying frontend ------------

Preparing to deploy:
	Created staging directory at: 'C:\Users\mkyong\AppData\Local\Temp\appcfg7432687551.tmp'
	Scanning for jsp files.
	Compiling jsp files.
	Scanning files on local disk.
	Initiating update.
	Cloning 2 static files.
	Cloning 46 application files.

Deploying:
	Uploading 12 files.
	Uploaded 3 files.
	Uploaded 6 files.
	Uploaded 9 files.
	Uploaded 12 files.
	Initializing precompilation...
	Sending batch containing 11 file(s) totaling 44KB.
	Sending batch containing 1 blob(s) totaling 1KB.
	Deploying new version.

Verifying availability:
	Will check again in 1 seconds.
	Will check again in 2 seconds.
	Will check again in 4 seconds.
	Closing update: new version is ready to start serving.

Updating datastore:
	Uploading index definitions.

Deployment completed successfully 

网址:http://mkyong-struts2gae.appspot.com/User/Login.action

gae struts2 example run on GAENote
Finally, finished this long article. The overall integration is not much difficult, just need to fix Struts2 ognl security and TextBlock issues, hope Struts2’s team can fix this in future.

下载源代码

由于文件很大,所有 Struts2 jars 都被排除在外,需要手动下载。

Download – Struts2GoogleAppEngine.zip (23 KB)

参考

  1. Struts2 hello world 示例
  2. Google App Engine+Java hello world 示例,使用 Eclipse
  3. Apache Struts
  4. GAE 上的支柱 2

gae struts2

谷歌应用引擎教程

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/google-app-engine-tutorial/

Google App Engine Logo

Google App Engine ,一个云计算平台,用于在现有的 Google 基础设施中托管 web 应用程序,它易于扩展、管理和自由使用多达预定义的消耗资源,并且它支持 Java。如需额外收费,请参考此 GAE 计费

在这一系列教程中,我们将向您展示一系列教程,帮助您开始使用 Java 编程 Google App Engine。

Note
All GAE tutorials are developed with “Eclipse 3.7 + Google Plugin for Eclipse” and “Google App Engine Java SDK 1.6.3.1“.

1.快速启动

向谷歌应用引擎问好。

2.GAE +支柱 1 和 2

Struts 1 & 2 框架集成和你可能遇到的一些常见错误。

3.GAE + JSF 2

JSF 新协议框架集成和你可能遇到的一些常见错误。

4.GAE +春天

Spring 框架集成。

5.数据存储

在 Java 的 GAE 中,可以通过数据存储低级 api、JDO 或 JPA 将数据存储在“数据存储”中。在这个例子中,我们将使用 Spring MVC 进行演示。

6.常见问题

谷歌应用引擎中的一些常见问题。

参考

  1. GAE:Java 入门
  2. GAE 计费
  3. GAE 代码实验室
  4. GAE 白名单罐子
  5. 谷歌应用引擎维基百科

gae tutorials

Gradle 和 JUnit 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/unittest/gradle-and-junit-example/

在 Gradle 中,您可以像这样声明 JUnit 依赖关系:

build.gradle

 apply plugin: 'java'

	dependencies {
		testCompile 'junit:junit:4.12'
	} 

默认情况下,JUnit 附带了一个hamcrest-core的捆绑副本

 $ gradle dependencies --configuration testCompile

testCompile - Compile classpath for source set 'test'.
\--- junit:junit:4.12
     \--- org.hamcrest:hamcrest-core:1.3 

1.Gradle + JUnit + Hamcrest

通常,我们需要有用的hamcrest-library库,所以,最好排除hamcrest-core的 JUnit 捆绑副本,包括原始的hamcrest-core库。再次回顾更新后的pom.xml

build.gradle

 apply plugin: 'java'

	dependencies {
		testCompile('junit:junit:4.12'){
			exclude group: 'org.hamcrest'
		}
		testCompile 'org.hamcrest:hamcrest-library:1.3'
	} 

再次检查依赖性。

 $ gradle dependencies --configuration testCompile

testCompile - Compile classpath for source set 'test'.
+--- junit:junit:4.12
\--- org.hamcrest:hamcrest-library:1.3
     \--- org.hamcrest:hamcrest-core:1.3 

参考

  1. 显示项目依赖关系
  2. JUnit–与 Gradle 一起使用

gradle hamcrest junit (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190223082648/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

gradle–Spring 4 MVC Hello World 示例–注释

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/gradle-spring-4-mvc-hello-world-example-annotation/

gradle-spring-logo

在本教程中,我们将以之前的 Gradle + Spring MVC XML 示例为例,将其重写为支持@JavaConfig 注释配置,不再需要 XML 文件。

这个例子只能在 Servlet 3.0+容器中运行,比如 Tomcat 7 或 Jetty 9。

使用的技术:

  1. Gradle 2.0
  2. 弹簧 4.1.6 释放
  3. Tomcat 7 或 Jetty 9
  4. Eclipse 4.4
  5. JDK 1.7
  6. 回溯 1.1.3
  7. 助推器 3

1.项目结构

下载项目源代码并查看项目文件夹结构:

spring4-mvc-gradle-project-anno

P.S 不再有类似web.xml或 Spring XML 配置文件的 XML 文件。

2. Gradle

2.1 查看build.gradle文件,这应该是不言自明的。

build.gradle

 apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
//apply plugin: 'jetty' //too old, Jetty 6, use gretty plugin
apply plugin: 'org.akhikhl.gretty'

// JDK 7
sourceCompatibility = 1.7
targetCompatibility = 1.7

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile 'ch.qos.logback:logback-classic:1.1.3'
    compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
    compile 'javax.servlet:jstl:1.2'

    //include in compile only, exclude in the war
    providedCompile 'javax.servlet:servlet-api:2.5'
}

//Gretty Embedded Jetty
buildscript {
  repositories {
    jcenter()
  }

  dependencies {
    classpath 'org.akhikhl.gretty:gretty:+'
  }
}

// Don't use Jetty8, even it's a servlet 3.0+ container, 
// but not support non-jar WebApplicationInitializer scanning.
// It will cause "No Spring WebApplicationInitializer types detected on classpath"
gretty {
  port = 8080
  contextPath = 'spring4'
  servletContainer = 'jetty9' //tomcat7 or tomcat8
}

//For Eclipse IDE only
eclipse {

  wtp {
    component {

      //define context path, default to project folder name
      contextPath = 'spring4'

    }

  }
} 

2.2 使这个项目支持 Eclipse IDE。现在,您可以将项目导入到 Eclipse IDE 中。

 your-project$ gradle eclipse 

3.弹簧@配置

Spring @Configuration 及其 XML 等价物。

3.1 Spring annotation 配置扫描服务类。

SpringRootConfig.java

 package com.mkyong.helloworld.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({ "com.mkyong.helloworld.service" })
public class SpringRootConfig {
} 

XML 等价物。

spring-core-config.xml

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd ">

	<context:component-scan base-package="com.mkyong.helloworld.service" />

</beans> 

3.2 扩展抽象类WebMvcConfigurerAdapter

SpringWebConfig.java

 package com.mkyong.helloworld.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc //<mvc:annotation-driven />
@Configuration
@ComponentScan({ "com.mkyong.helloworld.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**")
                        .addResourceLocations("/resources/");
	}

	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver 
                         = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/jsp/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}

} 

XML 等价物。

spring-web-config.xml

 <beans 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd ">

	<context:component-scan base-package="com.mkyong.helloworld.web" />

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/views/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean>

	<mvc:resources mapping="/resources/**" location="/resources/" />

	<mvc:annotation-driven />

</beans> 

4.Servlet 3.0+容器

创建一个ServletInitializer类,Servlet 3.0+容器会自动拾取这个类并运行它。这是web.xml的替代类

 package com.mkyong.helloworld.servlet3;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.mkyong.helloworld.config.SpringRootConfig;
import com.mkyong.helloworld.config.SpringWebConfig;

public class MyWebInitializer extends
		AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { SpringRootConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { SpringWebConfig.class };
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

} 

XML 等价物。

web.xml

 <web-app  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>Gradle + Spring MVC Hello World</display-name>
	<description>Spring MVC web application</description>

	<!-- For web context -->
	<servlet>
		<servlet-name>hello-dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-mvc-config.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>hello-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- For root context -->
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-core-config.xml</param-value>
	</context-param>

</web-app> 

Note
There is no change in the Spring controller, logback and JSP files, so, the source code will not repeat here, please refer to the previous Gradle + Spring MVC XML example for complete source code.

5.演示

5.1 运行本项目。启动嵌入式 Jetty 容器的问题。

Terminal

 your-project$ gradle jettyRun

21:56:34 INFO  Jetty 9.2.10.v20150310 started and listening on port 8080
21:56:34 INFO  spring4 runs at:
21:56:34 INFO    http://localhost:8080/spring4
Press any key to stop the server.
> Building 87% > :jettyRun 

5.2 http://localhost:8080/spring 4/

spring-4-mvc-gradle-demo1

5.3 http://localhost:8080/spring 4/hello/mkyong . com

spring4-mvc-gradle-demo2

下载源代码

Download It – spring4-mvc-gradle-annotation-hello-world.zip (39 KB)GitHub link – spring4-mvc-gradle-annotation-hello-world.git

参考

  1. 维基百科–Java servlet
  2. Spring Web MVC 参考资料
  3. Gradle–eclipse WTP
  4. Gradle–Eclipse 插件
  5. Gradle–Jetty 插件
  6. Gradle–Gretty 插件
  7. 格雷迪–格雷迪配置

gradle hello world servlet 3 spring config spring mvc

Spring MVC hello world 示例(Gradle 和 JSP)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/gradle-spring-mvc-web-project-example/

本教程向您展示了如何使用 Jakarta 服务器页面(JSP;以前的 JavaServer Pages)模板。

使用的技术和工具:

  • Java 11
  • 释放弹簧
  • JSP
  • JSTL 1.2
  • Servlet API 4.0.1
  • Bootstrap 5.2.0 (webjars)
  • 智能理念
  • Gradle 7.5.1
  • 用于嵌入式 servlet 容器的 Gradle Gretty 插件 3 . 0 . 9(Tomcat 9 和 Jetty 9.4)
  • 弹簧测试 5.2.22 .释放
  • 哈姆克雷斯特 2.2
  • JUnit 5.9

目录:


本教程不是 Spring Boot 应用,只是纯 Spring Web MVC!

1。目录结构

下面是这个项目的标准 Java 目录结构。

directory structure

2。项目依赖性

以下是该项目的核心依赖项;spring-webmvc依赖是必须的,但是其他的依赖依赖于你的项目需求。

  • spring-webmvc–用于 Spring core 相关的 web 组件。
  • jstl–对于雅加达标准标签库(JSTL;原名 JavaServer Pages 标准标签库)。
  • org.webjars.bootstrap–用于 WebJars 管理客户端 web 库,例如 bootstrap。
  • javax.servlet-api–我们需要servlet-api来编译 web 应用程序,设置为compileOnly范围;通常,嵌入式服务器会提供这种功能。
  • org.gretty–使用嵌入式 servlet 容器运行这个项目,比如 Tomcat 9 或 Jetty 9.4。

为什么是 Gretty 3 插件?
最新的 Gretty 4 插件只支持 Tomcat 10,而 Spring MVC 5 我们需要 Tomcat 8.5 或 9,所以我们会坚持使用更老的 Gretty 3。

为什么 Spring Web MVC 5 不运行 o Tomcat 10?

  • Tomcat 10 在包jakarta.*下实现 Servlet 5 规范(Jakarta EE 9 的一部分)。
  • Spring Web MVC 5.x 在包javax.*下实现 Servlet 4 规范(Jakarta EE 8 的一部分)。

Spring 5 还是靠javax.servlet.*,最新的 Tomcat 10 靠jakarta.servlet。简而言之,Spring 5 无法与 Tomcat 10 兼容,因为软件包从javax.*重命名为jakarta.*

延伸阅读

build.gradle

 plugins {
	id 'org.gretty' version '3.0.9'
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'

// JDK 11
sourceCompatibility = 11
targetCompatibility = 11

repositories {
    mavenCentral()
}

dependencies {
	compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
	implementation 'javax.servlet:jstl:1.2'
	implementation 'org.springframework:spring-webmvc:5.2.22.RELEASE'
	implementation 'org.webjars:bootstrap:5.2.0'
	testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
	testImplementation 'org.springframework:spring-test:5.2.22.RELEASE'
	testImplementation 'org.hamcrest:hamcrest-core:2.2'
}

gretty {
	httpPort = 8080
	contextPath = '/'
	//servletContainer = 'jetty9.4'
	servletContainer = 'tomcat9'
}

test {
	useJUnitPlatform()
} 

3。项目依赖关系——树形格式

再次检查树结构中的项目依赖关系。

Terminal

 gradle dependencies --configuration compileClasspath

> Task :dependencies

------------------------------------------------------------
Root project 'spring-mvc-hello-world-jsp'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
+--- javax.servlet:javax.servlet-api:4.0.1
+--- javax.servlet:jstl:1.2
+--- org.springframework:spring-webmvc:5.2.22.RELEASE
|    +--- org.springframework:spring-aop:5.2.22.RELEASE
|    |    +--- org.springframework:spring-beans:5.2.22.RELEASE
|    |    |    \--- org.springframework:spring-core:5.2.22.RELEASE
|    |    |         \--- org.springframework:spring-jcl:5.2.22.RELEASE
|    |    \--- org.springframework:spring-core:5.2.22.RELEASE (*)
|    +--- org.springframework:spring-beans:5.2.22.RELEASE (*)
|    +--- org.springframework:spring-context:5.2.22.RELEASE
|    |    +--- org.springframework:spring-aop:5.2.22.RELEASE (*)
|    |    +--- org.springframework:spring-beans:5.2.22.RELEASE (*)
|    |    +--- org.springframework:spring-core:5.2.22.RELEASE (*)
|    |    \--- org.springframework:spring-expression:5.2.22.RELEASE
|    |         \--- org.springframework:spring-core:5.2.22.RELEASE (*)
|    +--- org.springframework:spring-core:5.2.22.RELEASE (*)
|    +--- org.springframework:spring-expression:5.2.22.RELEASE (*)
|    \--- org.springframework:spring-web:5.2.22.RELEASE
|         +--- org.springframework:spring-beans:5.2.22.RELEASE (*)
|         \--- org.springframework:spring-core:5.2.22.RELEASE (*)
\--- org.webjars:bootstrap:5.2.0 

4。弹簧控制器

下面是一个 Spring Web MVC 控制器,用于处理对//hello/{name}的 Web 请求并显示消息。

HelloController.java

 package com.mkyong.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

    //@RequestMapping(value = "/", method = RequestMethod.GET)
    @GetMapping("/")
    public String defaultPage(ModelMap model) {
        return "hello";
    }

    //@RequestMapping(value = "/hello/{name:.+}", method = RequestMethod.GET)
    @GetMapping("/hello/{name:.+}")
    public ModelAndView hello(@PathVariable("name") String name) {

        ModelAndView model = new ModelAndView();
        model.setViewName("hello");
        model.addObject("message", name);

        return model;

    }

} 

5。弹簧配置

Spring 需要一个用于 JSP 页面的viewResolver bean。

SpringWebConfig.java

 package com.mkyong.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({ "com.mkyong.web" })
public class SpringWebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
    }

    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

} 

6。Spring DispatcherServlet

这个MyServletInitializer将由 Servlet 容器(例如 Jetty 或 Tomcat)自动检测。

MyServletInitializer.java

 package com.mkyong;

import com.mkyong.config.SpringWebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MyServletInitializer
      extends AbstractAnnotationConfigDispatcherServletInitializer {

  // services and data sources
  @Override
  protected Class<?>[] getRootConfigClasses() {
      return new Class[0];
  }

  // controller, view resolver, handler mapping
  @Override
  protected Class<?>[] getServletConfigClasses() {
      return new Class[]{SpringWebConfig.class};
  }

  @Override
  protected String[] getServletMappings() {
      return new String[]{"/"};
  }
} 

7 .。Spring MVC 和单元测试

Spring MVC 控制器的简单单元测试。

HelloControllerTest.java

 package com.mkyong;

import com.mkyong.config.SpringWebConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration(classes = {SpringWebConfig.class})
public class HelloControllerTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @BeforeEach
    void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testDefaultPage() throws Exception {

        MvcResult result = this.mockMvc.perform(get("/"))
                /*.andDo(print())*/
                .andExpect(status().isOk())
                .andReturn();

        ModelAndView modelAndView = result.getModelAndView();
        assertEquals("hello", modelAndView.getViewName());
        assertNull(modelAndView.getModel().get("message"));

    }

    @Test
    public void testHelloPage() throws Exception {

        MvcResult result = this.mockMvc.perform(get("/hello/mkyong"))
                .andExpect(status().isOk())
                .andReturn();

        ModelAndView modelAndView = result.getModelAndView();
        assertEquals("hello", modelAndView.getViewName());
        assertEquals("mkyong", modelAndView.getModel().get("message"));

    }

} 

8。JSP 和 JSTL

一个显示 hello world 消息的简单 JSP + JSTL 模板也展示了如何集成 webjars 的引导和定制 CSS 和 JS 文件。

webapp/WEB-INF/views/jsp/hello.jsp

 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Spring Web MVC and JSP</title>

<spring:url value="/resources/core/css/main.css" var="coreCss" />
<spring:url value="/webjars/bootstrap/5.2.0/css/bootstrap.min.css" var="bootstrapCss" />

<link href="${bootstrapCss}" rel="stylesheet" />
<link href="${coreCss}" rel="stylesheet" />
</head>

<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
  <a class="navbar-brand" href="#">Mkyong.com</a>
</nav>

<main role="main" class="container">

  <div class="starter-template">
      <h1>Spring Web MVC JSP Example</h1>
      <h2>
            <c:if test="${not empty message}">
                Hello ${message}
            </c:if>

            <c:if test="${empty message}">
                Welcome!
            </c:if>
      </h2>
  </div>

</main>

<spring:url value="/resources/core/js/main.js" var="coreJs" />
<spring:url value="/webjars/bootstrap/5.2.0/js/bootstrap.min.js" var="bootstrapJs" />

<script src="${coreJs}"></script>
<script src="${bootstrapJs}"></script>

</body>
</html> 

9。演示

转到终端,项目文件夹,运行gradle tomcatRunWar

Terminal

 gradle tomcatRunWar

//...
INFO: Completed initialization in 628 ms
17:19:14 INFO  Tomcat 9.0.58 started and listening on port 8080
17:19:14 INFO   runs at:
17:19:14 INFO    http://localhost:8080

> Task :tomcatRunWar
Press any key to stop the server. 

另外,试着用命令gradle jettyRunWar在嵌入式 Jetty 上运行 Spring Web MVC。

http://localhost:8080/

spring web mvc hello world JSP demo 1

http://localhost:8080/hello/mkyong

spring web mvc hello world JSP demo 2

10。下载源代码

$ git 克隆https://github.com/mkyong/spring-mvc/

$ cd spring-mvc-hello-world-jsp

$ gradle tomcatRunWar

或者

$度喷气式滑水道

请访问 http://localhost:8080/

请访问 http://localhost:8080/hello/mkyong

10。参考文献

gson——以流的形式读写 JSON

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/java/gson-streaming-to-read-and-write-json/

从 Gson 版本 1.6 开始,引入了两个新的类JsonReaderJsonWriter来提供对 JSON 数据的流处理。阅读此 Gson 流媒体文档以了解使用它的好处。

  • JsonWriter–将 JSON 写成一个流。
  • JsonReader–以流的形式读取 JSON。

1.JsonWriter

GsonExample1.java

 package com.mkyong;

import com.google.gson.stream.JsonWriter;

import java.io.FileWriter;
import java.io.IOException;

public class GsonExample1 {

    public static void main(String[] args) {

        try (JsonWriter writer = new JsonWriter(new FileWriter("c:\\projects\\user.json"))) {

            writer.beginObject();                   // {
            writer.name("name").value("mkyong");    // "name" : "mkyong"
            writer.name("age").value(29);           // "age" : 29

            writer.name("messages");                // "messages" :
            writer.beginArray();                    // [
            writer.value("msg 1");                  // "msg 1"
            writer.value("msg 2");                  // "msg 2"
            writer.value("msg 3");                  // "msg 3"
            writer.endArray();                      // ]

            writer.endObject();                     // }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

} 

输出

c:\projects\user.json

 {"name":"mkyong","age":29,"messages":["msg 1","msg 2","msg 3"]} 

2.JsonReader

令牌在流模式下,每一个 JSON 数据都被认为是一个单独的令牌。当你使用JsonReader来处理它的时候,每个令牌都会被顺序处理。举个例子,

 {
	"url":"www.mkyong.com"
} 
  • 令牌 1 = {
  • 令牌 2 = url
  • 令牌 3 = www.mkyong.com
  • 令牌 4 = }

GsonExample2.java

 package com.mkyong;

import com.google.gson.stream.JsonReader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class GsonExample2 {

    public static void main(String[] args) {

        try (JsonReader reader = new JsonReader(new FileReader("c:\\projects\\user.json"))) {

            reader.beginObject();

            while (reader.hasNext()) {

                String name = reader.nextName();

                if (name.equals("name")) {

                    System.out.println(reader.nextString());

                } else if (name.equals("age")) {

                    System.out.println(reader.nextInt());

                } else if (name.equals("messages")) {

                    // read array
                    reader.beginArray();

                    while (reader.hasNext()) {
                        System.out.println(reader.nextString());
                    }

                    reader.endArray();

                } else {
                    reader.skipValue(); //avoid some unhandle events
                }
            }

            reader.endObject();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
} 

输出

 mkyong
29
msg 1
msg 2
msg 3 

Note
Read more Gson examples

参考

在 Spring MVC 中处理重复的表单提交

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/handling-duplicate-form-submission-in-spring-mvc/

在最后一个 Spring MVC 表单处理的例子中,如果你刷新表单成功视图,大多数浏览器会提示一个弹出对话框来确认表单的重新提交。如果您单击“是”,表单将再次被重新提交,这种情况就是众所周知的重复表单提交。

图:提交重复表单的示例。

SpringMVC-Duplicate-Form-Submit

常见的解决方案是使用" Post/Redirect/Get "设计模式。如果表单提交成功,它将重定向到另一个 URL,而不是直接返回网页。

Note
Check the details explanation of Post/Redirect/Get Design Pattern in Wiki.

Spring MVC 中的 post/重定向/Get 设计模式

在本教程中,我们将向您展示如何应用 Spring MVC 中的" Post/Redirect/Get "设计模式来解决最后一个表单处理示例中的重复表单提交问题。

1.重复表单提交

见下面正常的表单声明,会遇到重复表单提交的问题。

文件:mvc-dispatcher-servlet.xml

 <bean 
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

   <bean class="com.mkyong.customer.controller.CustomerController">
	<property name="formView" value="CustomerForm" />
	<property name="successView" value="CustomerSuccess" />
   </bean>

   <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
             <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
             <value>.jsp</value>
        </property>
    </bean> 

在上面的代码片段中,CustomerController直接返回一个" CustomerSuccess "视图,而这个视图应该用重定向 URL 替换为

2.重定向视图

声明了一个评论视图,命名为“customersuccessredict”,并返回一个 URL“【CustomerSuccess.htm】T2”。

文件:spring-views.xml

 <beans ...>
   <!-- Redirect view --> 
   <bean id="customerSuccessRedirect" 
       class="org.springframework.web.servlet.view.RedirectView">
       <property name="url" value="CustomerSuccess.htm" />
    </bean>	 
</beans> 

3.弹簧配置

更新MVC-dispatcher-servlet . XML设置,将所有 Spring 的配置链接在一起。

  1. 将“成功视图”更新为新的重定向视图,命名为“客户成功重定向”。
  2. 声明一个“ XmlViewResolver ”来加载重定向视图。
  3. 为“InternalResourceViewResolver”和“ XmlViewResolver ”设置一个优先级顺序,否则“InternalResourceViewResolver”将始终匹配,并且不会让您的应用程序有机会调用“ XmlViewResolver ”。
  4. 声明一个"ParameterizableViewController"控制器来匹配重定向 URL 并向用户返回一个视图。由于“ControllerClassNameHandlerMapping”不会为任何内置 Spring 的控制器生成映射,所以您必须在“ SimpleUrlHandlerMapping ”中定义显式映射。

文件:mvc-dispatcher-servlet.xml

 <bean 
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

   <bean class="com.mkyong.customer.controller.CustomerController">
	<property name="formView" value="CustomerForm" />
	<property name="successView" value="customerSuccessRedirect" />

	<!-- it was
	<property name="successView" value="CustomerSuccess" />
	-->
   </bean>

   <!-- Redirect Controller -->
   <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/CustomerSuccess.htm">customerSuccessController</prop>
            </props>
        </property>
   </bean>

   <bean id="customerSuccessController" 
        class="org.springframework.web.servlet.mvc.ParameterizableViewController">
       <property name="viewName" value="CustomerSuccess" />
   </bean>

   <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
             <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
             <value>.jsp</value>
         </property>
         <property name="order" value="1" />
   </bean>

   <bean class="org.springframework.web.servlet.view.XmlViewResolver">
        <property name="location">
	      <value>/WEB-INF/spring-views.xml</value>
	 </property>
	 <property name="order" value="0" />
   </bean> 

4.它是如何工作的?

1.访问网址:http://localhost:8080/spring MVC/customer . htm

2.填写并提交表单。

3.返回“成功视图”,即“客户成功重定向”。

 <bean class="com.mkyong.customer.controller.CustomerController">
	<property name="formView" value="CustomerForm" />
	<property name="successView" value="customerSuccessRedirect" />
   </bean> 

4.“XmlViewResolver”匹配它并返回一个 URL 为“CustomerSuccess.htm”的“RedirectView”。

 <bean id="customerSuccessRedirect" 
       class="org.springframework.web.servlet.view.RedirectView">
       <property name="url" value="CustomerSuccess.htm" />
    </bean> 

5.“SimpleUrlHandlerMapping”匹配它并返回一个 ParameterizableViewController,“customerSuccessController”,返回视图名“ CustomerSuccess ”。

 <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/CustomerSuccess.htm">customerSuccessController</prop>
            </props>
        </property>
   </bean>
   <bean id="customerSuccessController" 
        class="org.springframework.web.servlet.mvc.ParameterizableViewController">
       <property name="viewName" value="CustomerSuccess" />
   </bean> 

6.“InternalResourceViewResolver”匹配它并返回最终视图“/we b-INF/pages/customer success . JSP”。

 <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
             <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
             <value>.jsp</value>
         </property>
         <property name="order" value="1" />
   </bean> 

7.网址改为http://localhost:8080/spring MVC/customer success . htm

8.尝试刷新成功表单页面,表单重新提交对话框将不再提示。

Note
The overall concept is return a redirect URL instead of a direct page.

下载源代码

Download it – SpringMVC-Duplicated-Form-Submission-Solution.zip (12KB)

参考

  1. 发布/重定向/获取设计模式
  2. Spring MVC 中的表单处理

duplicated form submission spring mvc

休眠–找不到 C3P0ConnectionProvider

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-could-not-find-c3p0connectionprovider/

问题

已将 Hibernate 配置为使用" c3p0 "连接池,但遇到以下警告:

 //...
2011-04-25_12:18:37.190 WARN  o.h.c.ConnectionProviderFactory - 
c3p0 properties is specificed, but could not find 

org.hibernate.connection.C3P0ConnectionProvider from the classpath,
 these properties are going to be ignored.
2011-04-25_12:18:37.191 INFO  o.h.c.DriverManagerConnectionProvider - 
Using Hibernate built-in connection pool (not for production use!)
//... 

貌似“org.hibernate.connection.C3P0ConnectionProvider”不见了?

解决办法

从 Hibernate v3.3 开始(如果没弄错的话),“ C3P0ConnectionProvider ”被移到另一个 jar 文件“ hibernate-c3p0.jar ”。你需要包含它,以使 Hibernate 支持 c3p0 连接池。

可以从 JBoss 公共资源库下载“ hibernate-c3p0.jar ”。

文件:pom.xml

 <project ...>

	<repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
		</repository>
	</repositories>

	<dependencies>

		<!-- Hibernate c3p0 connection pool -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-c3p0</artifactId>
			<version>3.6.3.Final</version>
		</dependency>

	</dependencies>
</project> 

Note
See this detail guide – “How to configure c3p0 connection pool in Hibernate“. ## 参考

  1. http://docs . JBoss . org/hibernate/core/3.3/API/org/hibernate/connection/C3 P0 connection provider . html
  2. http://sourceforge.net/projects/c3p0/

hibernate

休眠标准示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-criteria-examples/

Hibernate Criteria API 是 Hibernate 查询语言(HQL)的一个更加面向对象和优雅的替代品。对于有许多可选搜索标准的应用程序来说,这总是一个好的解决方案。

HQL 的例子和标准

这里有一个案例研究,使用可选的搜索标准(开始日期、结束日期和数量、按日期排序)来检索一个 StockDailyRecord 的列表。

1.HQL 的例子

在 HQL,您需要比较这是否是附加“where”语法的第一个标准,并将日期格式化为合适的格式。它的工作,但长代码是丑陋的,笨重的和容易出错的字符串连接可能会引起安全问题,如 SQL 注入。

 public static List getStockDailtRecord(Date startDate,Date endDate,
   Long volume,Session session){

   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
   boolean isFirst = true; 

   StringBuilder query = new StringBuilder("from StockDailyRecord ");

   if(startDate!=null){
	if(isFirst){
		query.append(" where date >= '" + sdf.format(startDate) + "'");
	}else{
		query.append(" and date >= '" + sdf.format(startDate) + "'");
	}
	isFirst = false;
   }

   if(endDate!=null){
	if(isFirst){
		query.append(" where date <= '" + sdf.format(endDate) + "'");
	}else{
		query.append(" and date <= '" + sdf.format(endDate) + "'");
	}
	isFirst = false;
   }

   if(volume!=null){
	if(isFirst){
		query.append(" where volume >= " + volume);
	}else{
		query.append(" and volume >= " + volume);
	}
	isFirst = false;
   }

   query.append(" order by date");
   Query result = session.createQuery(query.toString());

   return result.list();
} 

2.标准示例

在条件中,您不需要比较这是否是附加“where”语法的第一个条件,也不需要设置日期格式。代码行减少了,一切都以更优雅和面向对象方式处理。

 public static List getStockDailyRecordCriteria(Date startDate,Date endDate,
        Long volume,Session session){

	Criteria criteria = session.createCriteria(StockDailyRecord.class);
	if(startDate!=null){
		criteria.add(Expression.ge("date",startDate));
	}
	if(endDate!=null){
		criteria.add(Expression.le("date",endDate));
	}
	if(volume!=null){
		criteria.add(Expression.ge("volume",volume));
	}
	criteria.addOrder(Order.asc("date"));

	return criteria.list();
  } 

标准 API

让我们来看看一些流行的标准 API 函数。

1.标准基本查询

创建一个 criteria 对象,并从数据库中检索所有“StockDailyRecord”记录。

 Criteria criteria = session.createCriteria(StockDailyRecord.class); 

2.标准排序查询

结果按“日期”升序排序。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
    .addOrder( Order.asc("date") ); 

结果按“日期”降序排序。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
    .addOrder( Order.desc("date") ); 

3.标准限制查询

Restrictions 类提供了许多方法来进行比较操作。

限制. eq

确保值等于 10000。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
    .add(Restrictions.eq("volume", 10000)); 
限制。lt,le,gt,ge

确保音量小于 10000。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.lt("volume", 10000)); 

请确保音量小于或等于 10000。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.le("volume", 10000)); 

确保音量大于 10000。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.gt("volume", 10000)); 

请确保音量大于或等于 10000。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.ge("volume", 10000)); 
限制,比如

确保股票名称以“MKYONG”开头,后跟任意字符。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.like("stockName", "MKYONG%")); 
限制。介于

请确保该日期在开始日期和结束日期之间。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.between("date", startDate, endDate)); 
Restrictions.isNull,isNotNull

请确保卷为空。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.isNull("volume")); 

请确保卷不为空。

 Criteria criteria = session.createCriteria(StockDailyRecord.class)
   .add(Restrictions.isNotNull("volume")); 

许多其他的限制函数可以在这里找到。
https://www . hibernate . org/Hib _ docs/v3/API/org/hibernate/criterion/restrictions . html

3.结果分页标准

Criteria 提供了很少的函数来使分页变得非常容易。从第 20 条记录开始,从数据库中检索接下来的 10 条记录。

 Criteria criteria = session.createCriteria(StockDailyRecord.class);
criteria.setMaxResults(10);
criteria.setFirstResult(20); 

为什么不是标准!?

标准 API 确实带来了一些缺点。

1.性能问题

您无法控制 Hibernate 生成的 SQL 查询,如果生成的查询很慢,您很难调优查询,并且您的数据库管理员可能不喜欢它。

1.维护问题

所有的 SQL 查询都分散在 Java 代码中,当一个查询出错时,您可能要花时间在您的应用程序中查找问题查询。另一方面,存储在 Hibernate 映射文件中的命名查询更容易维护。

结论

没有什么是完美的,请考虑您的项目需求并明智地使用它。

Hibernate 数据过滤器示例–XML 和注释

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-data-filter-example-xml-and-annotation/

Hibernate 数据过滤器是一种创新的方式来过滤从数据库中检索的数据,以一种更可重用的方式和“可见性”规则。数据过滤器有一个唯一的名称,全局访问并接受过滤器规则的参数化值,您可以在 Hibernate 会话中启用和禁用它。

休眠数据过滤器示例

在本例中,它定义了一个数据过滤器,过滤指定日期的收集数据。Hibernate 数据过滤器可以在 XML 映射文件和注释中实现。

1.XML 映射文件中的 Hibernate 数据过滤器

用' filter-def '关键字定义一个数据过滤器,并接受一个日期参数。

 <filter-def name="stockRecordFilter">
     <filter-param name="stockRecordFilterParam" type="date"/>
</filter-def> 
XML 映射示例

一个 XML 映射文件示例,用于声明并将其分配给收集组。

 <hibernate-mapping>
 <class name="com.mkyong.common.Stock" table="stock" catalog="mkyong">
   ...
   <set name="stockDailyRecords" inverse="true" table="stock_daily_record">
      <key>
         <column name="STOCK_ID" not-null="true" />
      </key>
      <one-to-many class="com.mkyong.common.StockDailyRecord" />
    <filter name="stockRecordFilter" condition="date >= :stockRecordFilterParam"/>
   </set>
 </class>   

 <filter-def name="stockRecordFilter">
   <filter-param name="stockRecordFilterParam" type="date"/>
 </filter-def>
</hibernate-mapping> 

condition = " date>=:stockRecordFilterParam "中,“日期”是属于“StockDailyRecord”的一个属性。

2.批注中的休眠数据过滤器

用' @FilterDef '关键字定义一个数据过滤器,用 @ParamDef 接受一个日期参数。

 @FilterDef(name="stockRecordFilter", 
parameters=@ParamDef( name="stockRecordFilterParam", type="date" ) ) 
注释示例

要声明并将其分配给收集组的批注文件示例。

 ...
@Entity
@FilterDef(name="stockRecordFilter", 
parameters=@ParamDef( name="stockRecordFilterParam", type="date" ) )
@Table(name = "stock", catalog = "mkyong")
public class Stock implements java.io.Serializable {
         ...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	@Filter(
		name = "stockRecordFilter",
		condition="date >= :stockRecordFilterParam"
	)
	public Set<StockDailyRecord> getStockDailyRecords() {
		return this.stockDailyRecords;
	} 

condition = " date>=:stockRecordFilterParam "中,“日期”是属于“StockDailyRecord”的一个属性。

如何启用和禁用数据过滤器

启用数据过滤器。

 Filter filter = session.enableFilter("stockRecordFilter");
filter.setParameter("stockRecordFilterParam", new Date()); 

禁用数据过滤器。

 session.disableFilter("stockRecordFilter"); 

应用和实现日期过滤器

下面的代码片段展示了如何应用和实现数据过滤器。

 Session session = HibernateUtil.getSessionFactory().openSession();

        System.out.println("****** Enabled Filter ******");

        Filter filter = session.enableFilter("stockRecordFilter");
        filter.setParameter("stockRecordFilterParam", new Date());

        Stock stock = (Stock)session.get(Stock.class, 2);
        Set<StockDailyRecord> sets = stock.getStockDailyRecords();

        for(StockDailyRecord sdr : sets){
		System.out.println(sdr.getDailyRecordId());
		System.out.println(sdr.getDate());
	}

        System.out.println("****** Disabled Filter ******");

        session.disableFilter("stockRecordFilter");
        //clear the loaded instance and get Stock again, for demo only
        session.evict(stock);

        Stock stock2 = (Stock)session.get(Stock.class, 2);
        Set<StockDailyRecord> sets2 = stock2.getStockDailyRecords();

        for(StockDailyRecord sdr : sets2){
		System.out.println(sdr.getDailyRecordId());
		System.out.println(sdr.getDate());
	} 

输出

 ****** Enabled Filter ******
58
2010-01-31
****** Disabled Filter ******
60
2010-01-02
58
2010-01-31
63
2010-01-23
61
2010-01-03
... 

在本例中(包括 XML 和注释),在启用过滤器后,它的所有“StockDailyRecord”集合都将根据参数 date 进行过滤。

P . S filter . set parameter(" stockRecordFilterParam ",new Date());,当前的新日期是 2010-01-27。

hibernate

Hibernate SQL 方言集合

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-dialect-collection/

Hibernate SQL 方言告诉您的 Hibernate 应用程序应该使用哪种 SQL 语言与您的数据库进行对话。

1.DB2

 org.hibernate.dialect.DB2Dialect 

2.DB2 AS/400

 org.hibernate.dialect.DB2400Dialect 

3.DB2 OS390

 org.hibernate.dialect.DB2390Dialect 

4.一种数据库系统

 org.hibernate.dialect.PostgreSQLDialect 

5.关系型数据库

 org.hibernate.dialect.MySQLDialect 

6.带有 InnoDB 的 MySQL

 org.hibernate.dialect.MySQLInnoDBDialect 

7.带有 MyISAM 的 MySQL

 org.hibernate.dialect.MySQLMyISAMDialect 

8.Oracle 8

 org.hibernate.dialect.OracleDialect 

9.Oracle 9i/10g

 org.hibernate.dialect.Oracle9Dialect 

10.赛贝斯

 org.hibernate.dialect.SybaseDialect 

11.Sybase Anywhere

 org.hibernate.dialect.SybaseAnywhereDialect 

12.Microsoft SQL Server

 org.hibernate.dialect.SQLServerDialect 

13.SAP 数据库

 org.hibernate.dialect.SAPDBDialect 

14.Informix

 org.hibernate.dialect.InformixDialect 

15.HypersonicSQL

 org.hibernate.dialect.HSQLDialect 

16.安格尔

 org.hibernate.dialect.IngresDialect 

17.进步

 org.hibernate.dialect.ProgressDialect 

18.Mckoi SQL

 org.hibernate.dialect.MckoiDialect 

19.Interbase

 org.hibernate.dialect.InterbaseDialect 

20.点基础

 org.hibernate.dialect.PointbaseDialect 

21. FrontBase

 org.hibernate.dialect.FrontbaseDialect 

22.火鸟

 org.hibernate.dialect.FirebirdDialect 

Note
Refer to this Hibernate SQL dialects documentation for further information.hibernate

向控制台显示 Hibernate SQL–show _ SQL、format_sql 和 use_sql_comments

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-display-generated-sql-to-console-show_sql-format_sql-and-use_sql_comments/

Hibernate 有一个内置函数,可以将所有生成的 SQL 语句记录到控制台。您可以通过在 Hibernate 配置文件"hibernate.cfg.xml"中添加一个" show_sql "属性来启用它。这个函数对于基本的故障排除很有用,并且可以查看 Hibernate 在后面做了什么。

1.显示 sql

允许将所有生成的 SQL 语句记录到控制台

 <!--hibernate.cfg.xml -->
<property name="show_sql">true</property> 

输出

 Hibernate: insert into mkyong.stock_transaction 
(CHANGE, CLOSE, DATE, OPEN, STOCK_ID, VOLUME) 
values (?, ?, ?, ?, ?, ?) 

2.格式 _sql

格式化生成的 SQL 语句,使其更具可读性,但会占用更多的屏幕空间。😃

 <!--hibernate.cfg.xml -->
<property name="format_sql">true</property> 

输出

 Hibernate: 
    insert 
    into
        mkyong.stock_transaction
        (CHANGE, CLOSE, DATE, OPEN, STOCK_ID, VOLUME) 
    values
        (?, ?, ?, ?, ?, ?) 

3.使用 sql 注释

Hibernate 将把注释放在所有生成的 SQL 语句中,以提示生成的 SQL 试图做什么

 <!--hibernate.cfg.xml -->
<property name="use_sql_comments">true</property> 

输出

 Hibernate: 
    /* insert com.mkyong.common.StockTransaction
        */ insert 
        into
            mkyong.stock_transaction
            (CHANGE, CLOSE, DATE, OPEN, STOCK_ID, VOLUME) 
        values
            (?, ?, ?, ?, ?, ?) 

休眠配置文件

hibernate.cfg.xml完整的例子。

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.bytecode.use_reflection_optimizer">false</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">password</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyong</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="use_sql_comments">true</property>
    </session-factory>
</hibernate-configuration> 

Hibernate SQL 参数值怎么样?

这个基本的 SQL 日志对于正常的调试来说已经足够好了,但是它不能显示 Hibernate SQL 参数值。需要一些第三方库集成来将 Hibernate SQL 参数值显示到控制台或文件中。检查以下两篇文章:

  1. 如何显示 hibernate sql 参数值–P6Spy
  2. 如何显示 hibernate sql 参数值–Log4J

hibernate sql

hibernate–动态插入属性示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-dynamic-insert-attribute-example/

什么是动态插入

dynamic-insert 属性告诉 Hibernate 是否在 SQL INSERT 语句中包含空属性。让我们探讨一些例子来更清楚地了解它。

动态插入示例

1.动态插入=假

dynamic-insert 的默认值是 false,这意味着在 Hibernate 的 SQL INSERT 语句中包含空属性

例如,尝试为一个对象属性设置一些空值并保存它。

 StockTransaction stockTran = new StockTransaction();
        //stockTran.setPriceOpen(new Float("1.2"));
        //stockTran.setPriceClose(new Float("1.1"));
        //stockTran.setPriceChange(new Float("10.0"));
        stockTran.setVolume(2000000L);
        stockTran.setDate(new Date());
        stockTran.setStock(stock);

        session.save(stockTran); 

打开 Hibernate "show_sql "为 true,你会看到下面的 insert SQL 语句。

 Hibernate: 
    insert 
    into
        mkyong.stock_transaction
        (DATE, PRICE_CHANGE, PRICE_CLOSE, PRICE_OPEN, STOCK_ID, VOLUME) 
    values
        (?, ?, ?, ?, ?, ?) 

Hibernate 将为插入生成不必要的列 (PRICE_CHANGE,PRICE_CLOSE,PRICE_OPEN)。

2.动态插入=真

如果将 dynamic-insert 设置为 true,这意味着在 Hibernate 的 SQL INSERT 语句中排除空属性值

例如,尝试将一些空值设置到一个对象属性并再次保存它。

 StockTransaction stockTran = new StockTransaction();
        //stockTran.setPriceOpen(new Float("1.2"));
        //stockTran.setPriceClose(new Float("1.1"));
        //stockTran.setPriceChange(new Float("10.0"));
        stockTran.setVolume(2000000L);
        stockTran.setDate(new Date());
        stockTran.setStock(stock);

        session.save(stockTran); 

将 Hibernate“show _ SQL”设置为 true。您将看到不同的 insert SQL 语句。

 Hibernate: 
    insert 
    into
        mkyong.stock_transaction
        (DATE, STOCK_ID, VOLUME) 
    values
        (?, ?, ?) 

Hibernate 将只为插入生成必要的列(日期、股票 ID、数量)。

性能问题

在某些情况下,比如一个有数百列的非常大的表(遗留设计),或者一个表包含非常大的数据量,插入一些不必要的东西肯定会降低系统性能。

如何配置

您可以通过注释或 XML 映射文件配置动态插入属性值。

1.注释

 @Entity
@Table(name = "stock_transaction", catalog = "mkyong")
@org.hibernate.annotations.Entity(
		dynamicInsert = true
)
public class StockTransaction implements java.io.Serializable { 

2.XML 映射

 <class ... table="stock_transaction" catalog="mkyong" dynamic-insert="true">
        <id name="tranId" type="java.lang.Integer">
            <column name="TRAN_ID" />
            <generator class="identity" />
        </id> 

结论

这个小小的"动态插入"调整可能会提高您的系统性能,强烈建议这样做。但是,我脑子里的一个问题是,Hibernate 为什么默认设置为 false?

追踪

1.hibernate-动态更新属性示例

hibernate

hibernate–动态更新属性示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/

什么是动态更新

动态更新属性告诉 Hibernate 是否在 SQL UPDATE 语句中包含未修改的属性。

动态更新示例

1.动态更新=假

dynamic-update 的默认值是 false,这意味着在 Hibernate 的 SQL update 语句中包含未修改的属性

例如,获取一个对象并尝试修改它的值和更新它。

 Query q = session.createQuery("from StockTransaction where tranId = :tranId ");
   q.setParameter("tranId", 11);
   StockTransaction stockTran = (StockTransaction)q.list().get(0);

   stockTran.setVolume(4000000L);
   session.update(stockTran); 

Hibernate 将生成下面的更新 SQL 语句。

 Hibernate: 
    update
        mkyong.stock_transaction 
    set
        DATE=?,
        PRICE_CHANGE=?,
        PRICE_CLOSE=?,
        PRICE_OPEN=?,
        STOCK_ID=?,
        VOLUME=? 
    where
        TRAN_ID=? 

Hibernate 将更新所有未修改的列。

2.动态更新=真

如果将 dynamic-insert 设置为 true,这意味着在 Hibernate 的 SQL update 语句中排除未修改的属性

例如,获取一个对象,尝试修改它的值并再次更新它。

 Query q = session.createQuery("from StockTransaction where tranId = :tranId ");
   q.setParameter("tranId", 11);
   StockTransaction stockTran = (StockTransaction)q.list().get(0);

   stockTran.setVolume(4000000L);
   session.update(stockTran); 

Hibernate 会生成不同的更新 SQL 语句。

 Hibernate: 
    update
        mkyong.stock_transaction 
    set
        VOLUME=? 
    where
        TRAN_ID=? 

Hibernate 将只更新修改过的列。

Performance issue
In a large table with many columns (legacy design) or contains large data volumes, update some unmodified columns are absolutely unnecessary and great impact on the system performance.

如何配置

您可以通过注释或 XML 映射文件配置“dynamic-update”属性。

1.注释

 @Entity
@Table(name = "stock_transaction", catalog = "mkyong")
@org.hibernate.annotations.Entity(
		dynamicUpdate = true
)
public class StockTransaction implements java.io.Serializable { 

2.XML 映射

 <class ... table="stock_transaction" catalog="mkyong" dynamic-update="true">
        <id name="tranId" type="java.lang.Integer">
            <column name="TRAN_ID" />
            <generator class="identity" />
        </id> 

结论

这个小小的"动态更新"调整肯定会提高您的系统性能,强烈推荐这样做。

追踪

1.hibernate-动态插入属性示例

Tags : hibernate

相关文章

休眠错误–需要使用 AnnotationConfiguration 实例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-an-annotationconfiguration-instance-is-required-to-use/

Hibernate 注释需要“AnnotationConfiguration”而不是普通的“Configuration()”来构建会话工厂。

 INFO: Configuration resource: /hibernate.cfg.xml
Initial SessionFactory creation failed.org.hibernate.MappingException: 
An AnnotationConfiguration instance is required to use <mapping class="com.mkyong.common.Stock"/>
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:19)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:11)
Caused by: org.hibernate.MappingException: An AnnotationConfiguration instance is required to use <mapping class="com.mkyong.common.Stock"/>
	at org.hibernate.cfg.Configuration.parseMappingElement(Configuration.java:1600)
	at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:1555)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1534)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1508)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1428)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1414)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more 

解决办法

1.下载 Hibernate 注释库

可以从 Hibernate 官网下载该库

或者

在 Maven 的 pom.xml 中添加依赖项

 <!-- Hibernate annotation -->
	<dependency>
		<groupId>hibernate-annotations</groupId>
		<artifactId>hibernate-annotations</artifactId>
		<version>3.3.0.GA</version>
	</dependency> 

页(page 的缩写)为了下载 Hibernate 注释库,您可能需要包含 JBoss 存储库。

 <repositories>
    <repository>
      <id>JBoss repository</id>
      <url>http://repository.jboss.com/maven2/</url>
    </repository>
  </repositories> 

2.使用 AnnotationConfiguration 构建会话工厂

正常的 Hibernate XML 文件映射使用配置()

 return new Configuration().configure().buildSessionFactory(); 

对于 Hibernate 注释,您必须将其更改为“AnnotationConfiguration”

 return new AnnotationConfiguration().configure().buildSessionFactory(); 
HibernateUtil.java

使用“AnnotationConfiguration”进行 Hibernate 注释应用的“HibernateUtil.java”的完整示例。

 package com.mkyong.persistence;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new AnnotationConfiguration().configure().buildSessionFactory();

        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
    	// Close caches and connection pools
    	getSessionFactory().close();
    }

} 

hibernate

休眠错误–线程“main”Java . lang . noclassdeffounderror 中的异常:antlr/antl Exception

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-exception-in-thread-main-java-lang-noclassdeffounderror-antlrantlrexception/

这是由于缺少 antlr 库造成的。这通常发生在你调用 Hibernate 的查询语句的时候。

 Exception in thread "main" java.lang.NoClassDefFoundError: antlr/ANTLRException
	at org.hibernate.hql.ast.ASTQueryTranslatorFactory.createQueryTranslator(ASTQueryTranslatorFactory.java:35)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:74)
	at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
	at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
	at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
	at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)
	at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1623)
	at com.mkyong.common.App.main(App.java:23)
Caused by: java.lang.ClassNotFoundException: antlr.ANTLRException
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 8 more 

解决办法

可以从 Antlr 官网下载该库

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>antlr</groupId>
		<artifactId>antlr</artifactId>
		<version>2.7.7</version>
	</dependency> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190308011741/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:net/SF/cglib/proxy/CallbackFilter

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-netsfcglibproxycallbackfilter/

一个常见的 Hibernate 错误,这是由于缺少依赖库 cglib 造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: net/sf/cglib/proxy/CallbackFilter
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: net/sf/cglib/proxy/CallbackFilter
	at org.hibernate.bytecode.cglib.BytecodeProviderImpl.getProxyFactoryFactory(BytecodeProviderImpl.java:33)
	at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactoryInternal(PojoEntityTuplizer.java:182)
	at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactory(PojoEntityTuplizer.java:160)
	at org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTuplizer.java:135)
	at org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.java:55)
	at org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping.<init>(EntityEntityModeToTuplizerMapping.java:56)
	at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:295)
	at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:434)
	at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:109)
	at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:55)
	at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: net.sf.cglib.proxy.CallbackFilter
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 15 more 

解决办法

你可以在这里下载图书馆-http://cglib.sourceforge.net/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2</version>
	</dependency> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190110062218/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/Apache/commons/collections/sequenced hashmap

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orgapachecommonscollectionssequencedhashmap/

一个常见的 Hibernate 错误,这是由于缺少依赖库——Apache Common Collection 造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/apache/commons/collections/SequencedHashMap
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/collections/SequencedHashMap
	at org.hibernate.mapping.Table.<init>(Table.java:33)
	at org.hibernate.cfg.Mappings.addTable(Mappings.java:165)
	at org.hibernate.cfg.HbmBinder.bindRootPersistentClassCommonValues(HbmBinder.java:290)
	at org.hibernate.cfg.HbmBinder.bindRootClass(HbmBinder.java:273)
	at org.hibernate.cfg.HbmBinder.bindRoot(HbmBinder.java:144)
	at org.hibernate.cfg.Configuration.add(Configuration.java:669)
	at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:504)
	at org.hibernate.cfg.Configuration.addResource(Configuration.java:566)
	at org.hibernate.cfg.Configuration.parseMappingElement(Configuration.java:1587)
	at org.hibernate.cfg.Configuration.parseSessionFactory(Configuration.java:1555)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1534)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1508)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1428)
	at org.hibernate.cfg.Configuration.configure(Configuration.java:1414)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.SequencedHashMap
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 17 more 

解决办法

你可以在这里下载图书馆-http://commons.apache.org/collections/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>commons-collections</groupId>
		<artifactId>commons-collections</artifactId>
		<version>3.2.1</version>
      </dependency> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190302163458/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/Apache/commons/logging/log factory

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orgapachecommonslogginglogfactory/

一个常见的 Hibernate 错误,这是由于缺少依赖库——公共日志记录造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
	at org.hibernate.cfg.Configuration.<clinit>(Configuration.java:120)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 4 more 

解决办法

你可以在这里下载图书馆-http://commons.apache.org/logging/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.1.1</version>
      </dependency> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190305140402/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/dom4j/document exception

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orgdom4jdocumentexception/

一个常见的 Hibernate 错误,这是由于缺少依赖库 dom4j 造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/dom4j/DocumentException
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: org/dom4j/DocumentException
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 3 more 

解决办法

你可以在这里下载图书馆-http://sourceforge.net/projects/dom4j/files/dom4j/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>dom4j</groupId>
		<artifactId>dom4j</artifactId>
		<version>1.6.1</version>
	</dependency> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190301211220/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Hibernate 错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/hibernate/annotations/common/reflection/reflection manager

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orghibernateannotationscommonreflectionreflectionmanager/

这是由于缺少 Hibernate commons 注释库造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: 
org/hibernate/annotations/common/reflection/ReflectionManager
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:19)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:11)
Caused by: java.lang.NoClassDefFoundError: org/hibernate/annotations/common/reflection/ReflectionManager
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.ReflectionManager
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 3 more 

解决办法

可以从 Hibernate 官网下载该库

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>hibernate-commons-annotations</groupId>
		<artifactId>hibernate-commons-annotations</artifactId>
		<version>3.0.0.GA</version>
	</dependency> 

页(page 的缩写)为了下载 Hibernate 公共注释库,您可能需要包含 JBoss 存储库。

 <repositories>
    <repository>
      <id>JBoss repository</id>
      <url>http://repository.jboss.com/maven2/</url>
    </repository>
  </repositories> 

hibernate (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190203090236/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

休眠错误–Java . lang . noclasdeffounderror:javax/transaction/synchron ization

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-java-lang-noclassdeffounderror-javaxtransactionsynchronization/

问题

这是由于缺少“jta.jar”造成的,通常发生在 Hibernate 事务开发中。

 java.lang.NoClassDefFoundError: javax/transaction/Synchronization
 at org.hibernate.impl.SessionImpl.<init>(SessionImpl.java:213)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:473)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:497)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:505)
 at com.mkyong.common.App.main(App.java:13)
Caused by: java.lang.ClassNotFoundException: javax.transaction.Synchronization
 at java.net.URLClassLoader$1.run(Unknown Source)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClassInternal(Unknown Source)
 ... 5 more 

解决办法

你可以从默认的 Maven central、JBoss 或 Java.net 库下载“jta.jar”。

1.Maven 中央存储库

 <dependencies>
        <dependency>
		<groupId>javax.transaction</groupId>
		<artifactId>jta</artifactId>
		<version>1.1</version>
	</dependency>
   </dependencies> 

2.JBoss Maven 资源库

添加 JBoss Maven 存储库

 <repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.com/maven2/</url>
		</repository>
	</repositories> 

并定义“jta.jar”明细。

 <dependencies>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>
	</dependencies> 

3.Java net Maven 知识库

添加 Java net Maven 资源库

 <repositories>
		<repository>
			<id>Java 2</id>
			<url>http://download.java.net/maven/2/</url>
		</repository>
	</repositories> 

并定义“ jta1.0.1B.jar”明细。

 <dependencies>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.0.1B</version>
		</dependency>
	</dependencies> 

Note
Alternately, you can include the “javaee.jar“, which can be found under J2EE SDK’s folder. The “javaee.jar” contains “javax/transaction/Synchronization” class as well.hibernate

posted @ 2024-11-01 16:32  绝不原创的飞龙  阅读(2)  评论(0编辑  收藏  举报