DROP TABLE IF EXISTS `user_`; CREATE TABLE `user_` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `CREATE_DATE_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `MODIFY_DATE_TIME` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `CREATE_USER_ID` int(10) NOT NULL, `MODIFY_USER_ID` int(10) NOT NULL, `DELETED` int(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `name_UNIQUE` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; INSERT INTO `user_` VALUES (1,'wheel','2012-07-20 07:03:20','0000-00-00 00:00:00',1,1,0),(2,'asmsupport','2012-07-20 07:03:20','0000-00-00 00:00:00',1,1,0);
<servlet> <servlet-name>jwmvc</servlet-name> <servlet-class>cn.wensiqun.wheel.mvc.dispatcher.ActionServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>jwmvc</servlet-name> <url-pattern>*.*</url-pattern> </servlet-mapping>
#数据库配置信息 jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=mysql ########################################################## # 是否是在运行时生成类,默认是true,当选择false的时候,需要使用 # wheel的maven插件wheel-maven-plugin,这个插件的作用就是将生成 # 的类添加到项目war包中,并且替换原有的class,使用这种方式的好处 # 就是减少系统的开销 ########################################################## generator.class.runtime=true ########################################################## # 将我们生成的class存入到指定路径,如果没有设置这个属性的值,将 # 不会输出生产的类。输出我们生成的class可以便于用反编译工具查看 # 对应的源码,这样可以更直观的清楚wheel的原理。当然也可能反编译 # 出来的源码内容不正确,具体原因可以参考 # http://www.wensiqun.com/2013/06/09/asmsupport_tutorial_3.html ########################################################## generator.class.output=D:/TEMP/mock_generated ########################################################## # Action类搜索路径,wheel会在这个路径里面查找被Action注解过的Class # 生成代理类,和SpringMVC中的 # # 类似。 # 这个路径也是我们存放ResultSetConverter的路径。 ########################################################## scan.base.path=cn.wensiqun.,jw. ########################################################## # Dao层接口的实现类的匹配前缀,比如接口com.wensiqun.wheel.TestDao # 如果我们设置 # dao.impl.class.suffix=impl. # dao.impl.class.suffix=JDBC # 那么我们将去寻找的实现类是com.wensiqun.wheel.impl.TestDaoJDBC, # 通过如下公式可以非常清楚: # 【实现类全名=声明类型的包 + "." + prefix + 声明类型名 + suffix】 ########################################################### dao.impl.class.prefix=impl. dao.impl.class.suffix=Impl service.impl.class.prefix=impl. service.impl.class.suffix=Impl
package jw.jwweb.mock.entity; public class User { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package jw.jwweb.mock.utils; import java.sql.ResultSet; import java.sql.SQLException; import jw.jwweb.mock.entity.User; import cn.wensiqun.wheel.util.rs.AbstractResultSetConverter; public class UserResultConverter extends AbstractResultSetConverter { @Override protected User convertToEntity(ResultSet rs) throws SQLException { User user = new User(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); return user; } }
这里要注意,public class UserResultConverter extends AbstractResultSetConverter这里的AbstractResultSetConverter应该加个泛型为:AbstractResultSetConverter。不知道为什么,这个代码高亮工具没法加
所有想要将Result转换成实体类的都可以通过这种方式实现,使用的时候也非常方便,只要调用ResultSetConverterContext.convertToEntities(User.class, rs)就能返回对应的List了。主要归功于Wheel在系统初始化的时候就已经找到所有Coverter并且实例化了。这里要注意的是每一个Converter在系统运行的时候只有一个实例,并且没有线程同步。user = user_ AS u user.id = u.id user.name = u.name all.user = SELECT ${user.id},${user.name} FROM ${segment.user}这里的properties文件的命名是规则是 DAO class name + SQL.properties,并且要和dao的class放在同一个包下,也就是说这里我们还有一个Dao叫做MockDaoImpl。 我们可以看到sql的properties文件中可以用占位符的方式,也就是说将${...}这部分内容替换成properties中对应的内容。那么如何在DAO中使用这些SQL呢,接下来就进入DAO的编写。
package jw.jwweb.mock.dao.impl; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import cn.wensiqun.wheel.db.template.MySQLTemplate; import cn.wensiqun.wheel.util.rs.ResultSetConverterContext; import jw.jwweb.mock.dao.MockDao; import jw.jwweb.mock.entity.User; public class MockDaoImpl extends MySQLTemplate implements MockDao { @Override public void insertUser(User user) { } @Override public void deleteUser(User user) { } @Override public void updateUser(User user) { } @Override public List allUser() throws Exception{ PreparedStatement prepareStatement = getStatement(getSql("all.user")); ResultSet rs = prepareStatement.executeQuery(); return ResultSetConverterContext.convertToEntities(User.class, rs); } @Override public List fuzzyQueryUser(User user) { // TODO Auto-generated method stub return null; } }有用我用的是Mysql所以这里我继承了MySQLTemplate这个类,这里还有OracleTemplate类,是Oracle的实现,当然也可以自定义实现。在Wheel中不同数据库的DBTemplate的主要区别是在于分页和获取最新插入的数据的自动增长列的值,在这里不详细介绍如何实现一个Template,在后续教程中将继续讲述。 这里只简单的实现下allUser方法,我们可以看到,getSql这个方法的调用,就是获取MockDaoImplSQL.properties中all.user所对应的sql。而getStatement就是获取sql对应的PreparedStatement,在wheel中所有的Statment都是基于PreparedStatement的封装。getStatement方法后面还有一个变元的参数,是传入sql中对应位置的值的,也就是"?"下对应的值,位置的顺序要一一对应上。
package jw.jwweb.mock.service.impl; import java.util.List; import jw.jwweb.mock.dao.MockDao; import jw.jwweb.mock.dao.impl.MockDaoImpl; import jw.jwweb.mock.entity.User; import jw.jwweb.mock.service.MockService; import cn.wensiqun.wheel.annotation.DAO; import cn.wensiqun.wheel.annotation.Singleton; import cn.wensiqun.wheel.annotation.Transaction; @Singleton public class MockServiceImpl implements MockService { @DAO private MockDao mockDao; @Transaction @Override public List getUsers() throws Exception { return mockDao.allUser(); } @Transaction @Override public void addUser() throws Exception { } }这里是Service层的实现,我们可以看到有三个注解, @Singleton @DAO @Transaction。下面一一解释这几个注解的作用.
这里如果配置了dao.impl.class.convert.method则dao.impl.class.prefix和dao.impl.class.suffix将无效,也就是说dao.impl.class.convert.method优先级更高
假设我们有个静态方法:package jw.jwweb.mock public class Utils{ public static String convert(String interfaceFullName){ return interfaceFullName+"Impl" } }我们配置dao.impl.class.convert.method=jw.jwweb.mock.Utils.convert, 那么wheel就会找到实现类的类名是jw.jwweb.mock.dao.MockDaoImpl。
package jw.jwweb.mock.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jw.jwweb.mock.entity.User; import jw.jwweb.mock.service.impl.MockServiceImpl; import cn.wensiqun.wheel.annotation.Service; import cn.wensiqun.wheel.mvc.annotation.Action; import cn.wensiqun.wheel.mvc.annotation.DefaultResultType; import cn.wensiqun.wheel.mvc.annotation.RequestMethod; import cn.wensiqun.wheel.mvc.annotation.UrlMapping; import cn.wensiqun.wheel.mvc.aware.HttpServletRequestAware; import cn.wensiqun.wheel.mvc.aware.HttpServletResponseAware; @Action("/MockServlet") public class MockServletAction implements HttpServletRequestAware, HttpServletResponseAware{ @Service(MockServiceImpl.class) private MockServiceImpl mockService; private HttpServletRequest request; private HttpServletResponse response; @UrlMapping( value= {"/execute.action", "/process.action"}, method = {RequestMethod.POST, RequestMethod.GET}, result= {"JSP_RES", "Redirect_RES", "plaintext_RES", "html_RES", "json_RES", "velocity_RES"}, resultType = {DefaultResultType.JSP, DefaultResultType.REDIRECT, DefaultResultType.PLAINTEXT, DefaultResultType.HTML, DefaultResultType.JSON, DefaultResultType.VELOCITY}, path= {"/servlet/test.jsp", "/servlet/test.jsp", "", "", "", "/WEB-INF/test.vm"} ) public String execute() throws IOException { String type = request.getParameter("type"); String userStr = ""; try { List users = mockService.getUsers(); if(users != null){ for(User u : users){ userStr += u.getName() + " "; } } } catch (Exception e) { userStr = "error read user!" + e.getMessage(); } if("FORWARD".equals(type)){ request.setAttribute("message", userStr + "i'm from forward"); return "JSP_RES"; }else if("REDIRECT".equals(type)){ return "Redirect_RES"; }else if("PLAINTEXT".equals(type)){ PrintWriter out = response.getWriter(); out.println("{\"success\" : true, \"message\" : " + userStr + "\"i'm from PLAINTEXT\"}"); out.close(); return "plaintext_RES"; }else if("VELOCITY".equals(type)){ request.setAttribute("resultMessage", userStr + " I'm from Velocity."); return "velocity_RES"; }else if("JSON".equals(type)){ Map<String, String> result = new HashMap<String, String>(); result.put("message", userStr + " I'm from JSON"); request.setAttribute(DefaultResultType.JSON, result); return "json_RES"; }else{ PrintWriter out = response.getWriter(); out.println(""); out.println("HTML Test"); out.println("" + userStr + "I'm from HTML"); out.println(""); out.close(); return "html_RES"; } } @Override public void setHttpServletResponse(HttpServletResponse response) { this.response = response; } @Override public void setHttpServletRequest(HttpServletRequest request) { this.request = request; } }这段就是我们熟知的Action层,这一层所包含的内容非常多我们一一解释,首先是注入。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!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=ISO-8859-1"> <title>Success</title> </head> <body> <% Object obj = request.getAttribute("message"); String message = ""; if(obj==null){ message = "I'm from REDIRECT"; }else{ message = obj.toString(); } %> <%=message %> </body> </html>
<!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>Success</title> </head> <body> ${resultMessage} </body> </html>
URL | 结果 |
http://host/WheelSampleApp/MockServlet/process.action?type=FORWARD | 浏览器显示asmsupport wheel i'm from forward |
http://host/WheelSampleApp/MockServlet/execute.action?type=FORWARD | 浏览器显示asmsupport wheel i'm from forward |
http://host/WheelSampleApp/MockServlet/process.action?type=REDIRECT | 浏览器显示I'm from REDIRECT,同时浏览器url变成http://host/WheelSampleApp/servlet/test.jsp |
http://host/WheelSampleApp/MockServlet/execute.action?type=PLAINTEXT | 浏览器显示{"success" : true, "message" : asmsupport wheel "i'm from PLAINTEXT"} |
http://host/WheelSampleApp/MockServlet/process.action?type=VELOCITY | 浏览器显示asmsupport wheel I'm from Velocity. |
http://host/WheelSampleApp/MockServlet/process.action?type=JSON | 浏览器显示{"message":"asmsupport wheel I'm from JSON"} |
http://host/WheelSampleApp/MockServlet/process.action?type=HTML | 浏览器显示asmsupport wheel I'm from HTML |