1. 准备安装文件
以下为需要准备的文件清单,从相应网址下载到本地,表格中列出的版本号是截止到2012年5月6日的最新版本。
序号 | 库类型 | 版本 | 文件名 | 下载地址 |
1 | Struts2 | 2.3.3 | struts-2.3.3-all.gz | http://struts.apache.org/ |
2 | Spring | 3.1.0 | spring-framework-3.1.1.RELEASE-with-docs.zip | http://springframework.org/ |
3 | Mybatis | 3.1.1 | mybatis-3.1.1-bundle.zip mybatis-spring-1.1.1-bundle.zip mybatis-generator-core-1.3.1-bundle.zip | http://code.google.com/p/mybatis/ |
4 | jquery | 1.7.2 | jquery-1.7.2.js | http://jquery.com/ |
4 | Eclipse | eclipse-jee-indigo-SR2-win32.zip | http://www.eclipse.org/downloads/ | |
5 | tomcat | 7.0.27 | apache-tomcat-7.0.27-windows-x86.zip | http://tomcat.apache.org/ |
Struts2
下载包含了库和代码、例子的全包:struts-2.3.3-all.gz,大约在76m,文件较大,但其中的空应用例程可作为直接拷贝的参考。
Spring
下载包含了库和代码、例子的全包:spring-framework-3.1.1.RELEASE-with-docs.zip
MyBatis
2. 新建WEB工程
选择WEB下Dynamic Web Project类型的工程:
工程命名为EMS,其它选项保持默认。
文件夹名保持默认
勾上生成web.xml选项,其它保持默认。
最后得到一个如下组织的WEB工程.
补充:
在Java Resources/src目录上通过右键菜单将JAVA代码下编译输出目录修改至WebContent/WEB-INF/classes目录,与myEclipse的默认方式保持一致,便于实时发布,如果不做这一步class等文件不会自动输出到WEB-INF下。
3. 配置Tomcat服务器
切换Servers页签:
※ 建议不采用eclipse的应用发布功能,改用修改Tomcat配置文件的方式来实现发布,因此这里暂时不作选择。
在Eclipse中测试启动Tomcat服务器:
采用修改Tomcat配置的方式来发布应用(建议采用,这是相对快捷的发布
1、双击tomcat服务器,打开配置选项,将Server Location选项置为第二个:
2、用文本编辑器打开:D:\tomcat\apache-tomcat-7.0.27\conf\server.xml 文件,在Host节点之上增加虚拟目录描述:
…
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log." suffix=".txt"/>
<Context path="/ems" docBase="E:\workspace\EMS\WebContent" reloadable="true"/>
</Host>
</Engine>
</Service>
</Server>
3、在WebContent目录下新建一个默认JSP页面:NewFile.jsp,打印一行信息:Hello World!
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> Hello World! </body> </html> |
4、在eclipse中重启tomcat,在浏览器中敲入URL:http://localhost:8080/ems/NewFile.jsp
验证是否看到正确的输出信息。
配置TOMCAT管理界面
打开:D:\tomcat\apache-tomcat-7.0.27\conf\tomcat-users.xml文件,加入:
<tomcat-users>
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="admin" password="admin" roles="manager-gui,admin-gui"/>
</tomcat-users>
之后通过admin/admin即可登陆管理界面。
4. 配置Structs2
搭建环境
从已下载的struts-2.3.3-all.gz文件中解压出自带的一个空例程:struts2-blank,直接从展开的文件夹中复制内容过来:
1) 复制struts2-blank\WEB-INF\lib目录下的所有JAR包到该工程的WEB-INF/lib目录下
2) 打开struts2-blank\WEB-INF\web.xml,复制其中过滤器到该工程相同目录下web.xml,,让struts2在tomcat启动的时候加载:
… <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> … |
3) 重启Tomcat服务,观察输出的日志,当发现启动日志中包含有“org.apache.struts2”关键字,且无异常抛出,说明struts2的装载过程正常。
编写一个action验证配置正确性
1) 在src下新建action包:com.jsdz.action,包中新建测试action类,该类继承至ActionSupport,命名为: LoginAction,用作登陆跳转:
package com.jsdz.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String username ; private String password ; @Override public String execute() throws Exception { System.out.println("LoginAction execute invoked!"); if(username.equals("admin") && password.equals("1234") ) { System.out.println("user ok"); return SUCCESS; } else { System.out.println("user invalid"); return INPUT ; } } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } |
2) 在将LoginAction类配置到struts2的配置文件中,该文件同样可以从例程工程中拷贝过来简单修改:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="emspkg" extends="struts-default"> <action name="login" class="com.jsdz.action.LoginAction"> <result name="success">/main.jsp</result> <result name="input">/login.jsp</result> </action> </package> </struts> |
注意:此时的action实例还是由struts自己来维护,class取值包含完整的路径。
3) 新建两个JSP页面:login.jsp(登陆页面)、main.jsp(登陆成功页面,提示用户登陆成功).流程说明:用户输入用户名和密码,必须是admin/1234才给验证通过转到main.jsp页面,否则仍然返回到login.jsp页面。
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <s:form action="login" namespace="/" theme="simple"> username:<s:textfield name="username" size="20"/><br> password:<s:password name="password" size="20"/><br> <s:submit label="submit"></s:submit> </s:form>
</body> </html> |
※注意:标红的部分容易出错,namespace都带上相同的取值,s:form的action上不带.action.
main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 用户:${requestScope.username },欢迎您登陆 </body> </html> |
4) 在浏览器中敲入http://localhost:8080/ems/login.jsp进行验证.
增加异常处理机制
采用struts2自有的异常处理机制,避免所有地方加上try/catch。
1) 增加包com.jsdz.exception,并在其中增加自定义业务异常类BusinessException.java。
package com.jsdz.exception; public class BusinessException extends RuntimeException { private static final long serialVersionUID = 0xc1a865c45ffdc5f9L; public BusinessException(String frdMessage) { super(createFriendlyErrMsg(frdMessage)); } public BusinessException(Throwable throwable) { super(throwable); } public BusinessException(Throwable throwable, String frdMessage) { super(throwable); } private static String createFriendlyErrMsg(String msgBody) { String prefixStr = "抱歉,"; String suffixStr = " 请稍后再试或与管理员联系!"; StringBuffer friendlyErrMsg = new StringBuffer(""); friendlyErrMsg.append(prefixStr); friendlyErrMsg.append(msgBody); friendlyErrMsg.append(suffixStr); return friendlyErrMsg.toString(); } } |
2) 增加包com.jsdz. interceptor,增加一个异常转化的拦截器类:BusinessInterceptor.java。
package com.jsdz.interceptor; import java.io.IOException; import java.sql.SQLException; import com.jsdz.exception.BusinessException; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class BusinessInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("BusinessInterceptor intercept() invoked! "); before(invocation); String result = ""; try { result = invocation.invoke(); } catch (DataAccessException ex) { throw new BusinessException("数据库操作失败!"); } catch (NullPointerException ex) { throw new BusinessException("调用了未经初始化的对象或者是不存在的对象!"); } catch (IOException ex) { throw new BusinessException("IO异常!"); } catch (ClassNotFoundException ex) { throw new BusinessException("指定的类不存在!"); } catch (ArithmeticException ex) { throw new BusinessException("数学运算异常!"); } catch (ArrayIndexOutOfBoundsException ex) { throw new BusinessException("数组下标越界!"); } catch (IllegalArgumentException ex) { throw new BusinessException("方法的参数错误!"); } catch (ClassCastException ex) { throw new BusinessException("类型强制转换错误!"); } catch (SecurityException ex) { throw new BusinessException("违背安全原则异常!"); } catch (SQLException ex) { throw new BusinessException("操作数据库异常!"); } catch (NoSuchMethodError ex) { throw new BusinessException("方法末找到异常!"); } catch (InternalError ex) { throw new BusinessException("Java虚拟机发生了内部错误"); } catch (Exception ex) { throw new BusinessException("程序内部错误,操作失败!"); } after(invocation, result); return result ; } /** * 验证登陆等... * @param invocation * @return * @throws Exception */ public void before(ActionInvocation invocation) throws Exception { //... } /** * 记录日志等... * @param invocation * @return * @throws Exception */ public void after(ActionInvocation invocation,String result) throws Exception{ //... } } |
3) 在WebContent目录下新建error.jsp,代表出错跳转的页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>error</title> </head> <s:property value="exception.message"/> <body> </body> </html> |
页面简单的打印出异常信息。
4) 在struts.xml配置文件中加入拦截器及错误跳转指示:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="emspkg" namespace="" extends="struts-default"> <!--注册拦截器--> <interceptors> <interceptor name="businessInterceptor" class="com.jsdz.interceptor.BusinessInterceptor"/> <interceptor-stack name="mystack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="businessInterceptor"/> </interceptor-stack> </interceptors> <!-- 设置默认拦截器栈 --> <default-interceptor-ref name="mystack"/> <!-- 全局跳转页面 --> <global-results> <result name="error">/error.jsp</result> </global-results> <!-- 全局异常 --> <global-exception-mappings> <exception-mapping result="error" exception="java.lang.Exception"/> </global-exception-mappings> <action name="login" class="loginAction"> <result name="success">/main.jsp</result> <result name="input">/login.jsp</result> </action> </package> </struts> |
5) 在LoginAction的execute方法中故意加入会产生异常的代码,测试页面转向:
int i= 10/0 ;
结果跳转至error.jsp,并显示“抱歉,数学运算异常! 请稍后再试或与管理员联系!”。
5. 整合spring
复制struts-spring插件包
从struts-2.3.3-all.gz包中复制struts2-spring-plugin-2.3.3.jar、commons-logging-1.1.1.jar两个JAR文件到该工程的WEB-INF/lib目录下:
复制springJAR包
从spring-framework-3.1.1.RELEASE-with-docs.zip包中复制spring相关的JAR文件(6个)该工程的WEB-INF/lib目录下:
修改web.xml
在文件中增加spring监听器配置信息,让spring在tomcat启动的时候加载:
… <!-- spring监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- spring监听器,使用scrope=request 时必须加上 --> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> … |
注:如果要使用request or session scope bean,那么在web.xml里需要加上下面这段设置:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
否则就会出现org.springframework.beans.factory.BeanCreationException: Scope 'request' is not active for the current thread
这个时候启动一下tomcat,会报错,此时还缺少spring的配置文件:applicationContext.xml
创建applicationContext.xml
在WEB-INF目录下创建文件名:applicationContext.xml,内容如下,先保持空:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> </beans> |
测试重启tomcat服务,验证启动过程没有异常。
新建好package
在Java Resources -》 src下新建出如下package:
l com.jsdz.action --action
l com.jsdz.dao --数据库访问
l com.jsdz.exception --自定义异常
l com.jsdz.interceptor --拦截器
l com.jsdz.model --模型对象
l com.jsdz.service --业务接口
l com.jsdz.service.impl --业务接口实现
l com.jsdz.test --测试目录
l com.jsdz.util --工具类
l com.jsdz.xml --mybatis映射XML
在applicationContext.xml中添加组件注入选项
这里配置成spring中注解+自动扫描方式,相对XML文件配置简化得多。
@Repository:DAO层组件,@Service:业务层组件,@Controller:控制层组件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <context:component-scan base-package="com.jsdz" use-default-filters="false" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> </context:component-scan> </beans> |
通过这部分设置相应几类组件都自动装载注入,但依赖于代码上添加有注解。
将action的创建托管给spring容器
修改LoginAction.java代码,添加注解,使之能够被spring自动创建。
package com.jsdz.action; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; @Scope("request") @Controller("loginAction") public class LoginAction extends ActionSupport { private String username ; private String password ; @Override public String execute() throws Exception { System.out.println("LoginAction execute invoked!"); if(username.equals("admin") && password.equals("1234") ) { System.out.println("user ok"); return SUCCESS; } else { System.out.println("user invalid"); return INPUT ; } } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } |
修改struts.xml配置文件,使action的创建托管给spring。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="emspkg" namespace="/" extends="struts-default"> <action name="login" class="loginAction"> <result name="success">/main.jsp</result> <result name="input">/login.jsp</result> </action> </package> </struts> |
上面的class取值保持与@Controller("loginAction") 括号中的值一致,默认是类名首字母小写。
到此可以做两种测试:
1) 去掉LoginAction.java中的注解,验证spring是否能创建对象实例;
2) 修改LoginAction.java中注解的命名,验证login.jsp是否能访问到对应的action
验证业务组件的自动注入
1. 创建业务组件接口以及两个实现类:LoginService、LoginServiceImpl,LoginServiceImpl2在action中不再自己负责逻辑判断,提交给LoginService来处理业务。这里创建两个实现类主要是验证当有多个实现类时如何选择注入。
LoginService.java
package com.jsdz.service; import … @Scope("singleton") @Service("loginService") public interface LoginService { boolean IsLogin(String userName,String passWord ) ; } |
由于这个业务类中不包含任何成员变量,属于无状态类,因此可以定义创建为单实例。
LoginServiceImpl.java
package com.jsdz.service.impl; import … @Scope("singleton") @Service("loginServiceImpl") public class LoginServiceImpl implements LoginService { @Override public boolean IsLogin(String userName, String passWord) { System.out.println("LoginServiceImpl IsLogin invoked!"); if(userName.equals("admin") && passWord.equals("1234")) return true; return false; } } |
LoginServiceImpl2.java
package com.jsdz.service.impl; import … @Scope("singleton") @Service("loginServiceImpl2") public class LoginServiceImpl2 implements LoginService { @Override public boolean IsLogin(String userName, String passWord) { System.out.println("LoginServiceImpl2 IsLogin invoked!"); if(userName.equals("admin") && passWord.equals("admin")) return true; return false; } } |
修改LoginAction.java
package com.jsdz.action; …. @Scope("request") @Controller("loginAction") public class LoginAction extends ActionSupport { private String username ; private String password ; @Autowired @Qualifier("loginServiceImpl2") private LoginService loginService ; @Override public String execute() throws Exception { System.out.println("LoginAction execute invoked!"); //if(username.equals("admin") && password.equals("1234") ) if(loginService.IsLogin(username, password)) { System.out.println("user ok"); return SUCCESS; } else { System.out.println("user invalid"); return INPUT ; } } public LoginService getLoginService() { return loginService; } public void setLoginService(LoginService loginService) { this.loginService = loginService; } …….. } |
@Autowired:自动注入
@Qualifier:多个相同类型时选择注入哪一个。
6. 整合MyBatis
复制MyBatis的JAR包
从mybatis-3.1.1-bundle.zip包中复制mybatis-3.1.1.jar,加lib目录下6个JAR文件到该工程的WEB-INF/lib目录下。
(其中commons-logging-1.1.1.jar直接覆盖现有的)
安装MyBatis Generator插件
该插件安装后能基于数据库表生成mybatis的相关文件,省下不少手动编码的功夫。安装参考说明: http://code.google.com/p/mybatis/wiki/Generator
插件更新地址是:http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/eclipse/UpdateSite/
插件安装好之后,能在新建项目中找到图示条目:
创建数据库测试对象
这里使用的是ORACLE数据库。
--创建数据库模式 create user ems identified by "ems"; grant connect to ems; grant resource to ems; grant unlimited tablespace to ems; --创建表 create table T_USER ( USERID NUMBER(8) not null, USERNAME VARCHAR2(30), PASSWORD VARCHAR2(30), STATE NUMBER(3) default 0 ); alter table T_USER add constraint PK_USER primary key (USERID); comment on table T_USER is '用户表'; comment on column T_USER.USERID is '用户标识'; comment on column T_USER.USERNAME is '用户名'; comment on column T_USER.PASSWORD is '密码'; comment on column T_USER.STATE is '状态'; insert into t_user(userid,username,password,state) values(1,'admin','1234',0) ; insert into t_user(userid,username,password,state) values(2,'root','1234',0) ; insert into t_user(userid,username,password,state) values(3,'tom','1',0) ; insert into t_user(userid,username,password,state) values(4,'scott','tiger',0) ; insert into t_user(userid,username,password,state) values(5,'system','manger',0) ; commit; |
创建generatorConfig.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- 驱动程序(在classpath中已存在驱动的情况下不需要) --> <classPathEntry location="D:\\ojdbc14.jar" /> <context id="context1" targetRuntime="MyBatis3"> <!-- 注释--> <commentGenerator> <property name="suppressAllComments" value="true" /> <property name="suppressDate" value="true" /> </commentGenerator> <!-- 数据库连接 --> <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:orcl" userId="ems" password="ems" /> <!--允许数值类型转换成不同类型,否则都映射为BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- 模型文件 --> <javaModelGenerator targetPackage="com.jsdz.model" targetProject="EMS/src" > <property name="enableSubPackages" value="false" /> <!-- 当为true时,产生的代码文件将按照schema产生子文件夹 --> <property name="trimStrings" value="true" /> <!-- set变量时自动剔除空白 --> </javaModelGenerator> <!-- XML映射文件 --> <sqlMapGenerator targetPackage="com.jsdz.xml" targetProject="EMS/src"> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- DAO文件(mapper接口) --> <javaClientGenerator targetPackage="com.jsdz.dao" targetProject="EMS/src" type="XMLMAPPER"> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!-- 数据库表 --> <table schema="ems" tableName="T_USER" domainObjectName="User"> <property name="useActualColumnNames" value="false"/> </table> </context> </generatorConfiguration> |
通过generatorConfig.xml文件生成DAO对象、映射文件
在generatorConfig.xml上右键菜单,执行”Generate MyBatis/iBATIS Artifacts”项,自动在:xml,domain,dao三个文件夹中生成映射文件、模型pojo、DAO接口类。
JDBC驱动 JAR包
复制JDBC驱动 JAR包到工程中,这里是ORACLEojdbc14.jar
新建mybatis-config.xml
在src根目录下新建出mybatis-config.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" /> <property name="username" value="ems" /> <property name="password" value="ems" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/jsdz/xml/UserMapper.xml" /> </mappers> </configuration> |
以上配置文件中的内容仅用作单独测试mybatis时使用,到最后与spring整合后里面的内容基本用不上,可以直接注释掉。
做一个简单的查询测试
1) 准备一个工具类:MyBatisUtil.java 。这个文件在官方文档和各类教程中都有涉及到,主要用作创建session,到最后与spring整合后基本用不上。
MyBatisUtil.java
package com.jsdz.util; import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisUtil { private final static SqlSessionFactory sqlSessionFactory ; static { String resouce = "mybatis-config.xml"; Reader reader = null; try { reader = Resources.getResourceAsReader(resouce); } catch (IOException e) { System.out.println(e.getMessage()); } sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory ; } } |
2) 准备两个测试桩文件,一个为主测试类Test.java,调各个具体的测试类,今后可以复用,另外一个面向UserMapper类的测试。
TestMapperUser.java
package com.jsdz.test; import … public class TestMapperUser { static SqlSessionFactory sqlSessionFactory = null ; static { sqlSessionFactory = MyBatisUtil.getSqlSessionFactory(); } void testQueryByUserNameAndPassword() { SqlSession sqlSession = sqlSessionFactory.openSession(); try{ UserMapper mapper = sqlSession.getMapper(UserMapper.class) ; UserExample example = new UserExample(); example.clear(); example.or().andUsernameEqualTo("admin").andPasswordEqualTo("1234") ; List<User> lst = mapper.selectByExample(example) ; System.out.println("query item count:" + lst.size() ); for(User user:lst) { System.out.println(user.getUserid() + "," + user.getUsername() + "," + user.getPassword() ) ; } }finally{ sqlSession.close(); } } // end of testQueryByCondition } |
Test.java
package com.jsdz.test; import … public class Test { public static void main(String[] args) { TestMapperUser testMapperUser = new TestMapperUser(); testMapperUser.testQueryByUserNameAndPassword(); System.exit(0); } } |
3) 以Application方式运行Test.java文件,输出:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
query item count:1
1,admin,1234
说明可以查询到记录。
日志中提示log4j的告警,解决方法:
log4j属性文件
在src目录下创建文件:log4j.properties,内容如下
# Rules reminder: # DEBUG < INFO < WARN < ERROR < FATAL # Global logging configuration log4j.rootLogger=INFO, stdout # My logging configuration... log4j.logger.java.sql=DEBUG log4j.logger.org.apache.mybatis=DEBUG ## Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n |
以上设置sql输出和mybatis级别DEBUG模式,保证了日志中能打印出mybatis执行的SQL语句,方便跟踪。
完成MyBatis与Spring的整合
目标:
l 由 spring来创建session,避免过多的session创建、销毁代码编写;
l 由spring来管理事务
l 将mapper接口的实例化创建交由spring管理
1) 安装整合插件:从mybatis-spring-1.1.1-bundle.zip包中复制包到WEB-INF/lib目录下:
主JAR包是mybatis-spring-1.1.1.jar
lib子目录下依赖包也一并拷贝进去, Spring的包在前面过程中已导入了一部分,这里重复的部分剔除掉。
2) 复制数据库连接池相关的JAR包到WEB-INF/lib目录下:
这两个包可以从apache的官方网站上找到。
3) 修改spring的配置文件:applicationContext.xml,把下面的内容增加上去:
…. <!-- 定义数据源连接 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" /> <property name="username" value="busimon" /> <property name="password" value="busimon" /> <property name="maxActive" value="100"/> <property name="maxIdle" value="30"/> <property name="maxWait" value="500"/> <property name="defaultAutoCommit" value="true"/> </bean> <!-- 定义全局的事务控制 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启注解方式声明事务 --> <tx:annotation-driven /> <!-- 定义SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath*:com/jsdz/xml/*.xml" /> <property name="typeAliasesPackage" value="com.mybatis.model" /> </bean>
<!-- 自动扫描 mapper,允许自动注入(根据类型匹配),不需要逐个配置mapper --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.jsdz.dao" /> </bean> …. |
此时重启tomcat服务验证能正确启动起来。
由于已托管给spring来处理,mybatis-config.xml文件中的内容已经可以注释掉,仅保留头部即可。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- <environments default="development"> --> <!-- <environment id="development"> --> <!-- <transactionManager type="JDBC" /> --> <!-- <dataSource type="POOLED"> --> <!-- <property name="driver" value="oracle.jdbc.driver.OracleDriver" /> --> <!-- <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" /> --> <!-- <property name="username" value="ems" /> --> <!-- <property name="password" value="ems" /> --> <!-- </dataSource> --> <!-- </environment> --> <!-- </environments> --> <!-- <mappers> --> <!-- <mapper resource="com/jsdz/xml/UserMapper.xml" /> --> <!-- </mappers> --> </configuration> |
到此,struts2、spring、MyBatis的整合宣告成功!
7. 整合jQuery
1) 复制jquery-1.7.2.js文件到WebContent目录下,并改名为:jquery.js;
2) 编写测试JSP文件:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JQuery测试</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $(document).ready(function() { $("p").click(function() { $(this).hide(); }); }); </script> </head> <body> <p>点击我自动消失.</p> </body> </html> |
3)启动服务,测试URL: http://localhost:8080/ems/testjq.html
8. 实现struts JSON
1) 从struts2压缩包中复制struts2-json-plugin-2.3.3.jar 插件包到WEB-INF 的lib目录下;
2) 编写一个测试返回JSON消息的ACTION:
GetJsonUserAction.java
package com.jsdz.action; import org.apache.struts2.json.annotations.JSON; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.jsdz.model.User; import com.opensymphony.xwork2.ActionSupport; @Scope("request") @Controller("getJsonUserAction") @SuppressWarnings("serial") public class GetJsonUserAction extends ActionSupport { private String username; // 入参 private User user; // 返回客户端 @Override public String execute() throws Exception { this.user = new User(); if (username.equals("jack")) { this.user.setUserid(101); this.user.setUsername(username); this.user.setPassword("world"); this.user.setState((short) 0); } else { this.user.setUserid(100); this.user.setUsername(username); this.user.setPassword("hello"); this.user.setState((short) 1); } return SUCCESS; } @JSON(name = "USER") public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } } |
struts.xml文件修改:
<package name="emspkg" namespace="" extends="json-default"> <action name="getJsonUser" class="getJsonUserAction"> <result type="json"> <param name="excludeProperties">username</param> </result> </action> |
jsonuser.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>json user</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> function getUser() { $.post("getJsonUser", { username: $("#username").val() } , function( returnedData,status) { var userid = returnedData.USER.userid; var username = returnedData.USER.username; var password = returnedData.USER.password; var state = returnedData.USER.state; var result = "<table border='1'><tr><th>userid</th><th>username</th><th>password</th><th>state</th></tr>" + "<tr><td>"+ userid +"</td><td>"+ username +"</td><td>"+ password +"</td><td>"+ state +"</td></tr></table>" ; $("#gsonDIV").html(result) ; } ); } </script> </head> <body> <select id="username"> <option value="tom">tom</option> <option value="jack">jack</option> </select> <input type="button" onclick="getUser()" value="click to get user info"></input> <div id="gsonDIV"></div> </body> </html> |
测试JSP调用。
3) 编写一个返回son对象列表的ACTION:
从google code上下载gson包到WEB-INF/lib目录下:gson-2.1.jar
编写ACTION:
GetJsonUserListAction.java
package com.jsdz.action; import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.google.gson.Gson; import com.jsdz.model.User; import com.opensymphony.xwork2.ActionSupport; @Controller("getJsonUserListAction") @Scope("request") public class GetJsonUserListAction extends ActionSupport { /* 用于存放JSON生成后的字符串结果 */ private String jsonResult ; @Override public String execute() throws Exception { List<User> userList = new ArrayList<User>(); User user = new User(); user.setUserid(1); user.setUsername("ZHANG"); user.setPassword("1"); user.setState((short)0); userList.add(user); user = null ; user = new User(); user.setUserid(2); user.setUsername("Lee"); user.setPassword("12"); user.setState((short)0); userList.add(user); Gson gson = new Gson(); java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken<List<User>>() {}.getType(); String jsonStr = gson.toJson(userList,type) ; System.out.println("jsonStr=" +jsonStr ); this.jsonResult= jsonStr ; return SUCCESS ; } public String getJsonResult() { return jsonResult; } public void setJsonResult(String jsonResult) { this.jsonResult = jsonResult; } } |
修改stucts.xml
<action name="getJsonUserList" class="getJsonUserListAction"> <result type="json"></result> </action> |
增加测试JSP文件:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>json user list</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> function getUser() { $.post("getJsonUserList", { } , function(returnedData,status) { var result = "<table border='1'><tr><th>userid</th><th>username</th><th>password</th><th>state</th></tr>" ; var userList = eval('(' + returnedData.jsonResult + ")") ; for(var i=0; i< userList.length;i++) { var userid = userList[i].userid; var username = userList[i].username; var password = userList[i].password; var state = userList[i].state; result = result+ "<tr><td>"+ userid +"</td><td>"+ username +"</td><td>"+ password +"</td><td>"+ state +"</td></tr>" ; } result = result + "</table>" ; $("#gsonDIV").html(result) ; } ); } </script> </head> <body> <input type="button" onclick="getUser()" value="click to get user info"></input> <div id="gsonDIV"></div> </body> </html> |