在上一篇中我们演示了一个例子,简单的查询所有客户信息,在这里我们总结如下:
1.1 整合dao层 , mybatis和Spring整合:通过spring管理mapper接口
使用mapper的扫描器自动扫描mapper接口在spring中进行注册;
1.2 整理service层 :通过spring管理servie接口
通过配置方式将service接口配置在spring配置文件中,实现事务控制;
1.3 整合SpringMvc
由于SpringMvc是Spring的模块,不需要整合;
2.1 定义controller方法对于的URL
可以在Controller根路径定义,可以进行分类请求,即窄化请求映射;
例如: 访问地址 :http://localhost:8989/SpringMvcMybatis1Demo/clients/clientsList.action
@Controller @RequestMapping("/clients") public class FClientController { @Autowired private FClientService fcService; @RequestMapping("/clientsList") public ModelAndView clientsList() { ModelAndView view = new ModelAndView(); List<FClient> list; try { list = fcService.findClientList(); view.addObject("clients", list); view.setViewName("/clientindex.jsp"); } catch (Exception e) { view.addObject("error", e.getMessage()); view.setViewName("/error.jsp"); } return view; }}
3.1 返回ModelAndView
需要在方法结束时,定义ModelAndView,将model和view分别进行设置
例如:
@RequestMapping("/clientsList") public ModelAndView clientsList() { ModelAndView view = new ModelAndView(); List<FClient> list; try { list = fcService.findClientList(); view.addObject("clients", list); view.setViewName("/clientindex.jsp"); } catch (Exception e) { view.addObject("error", e.getMessage()); view.setViewName("/error.jsp"); } return view; }
3.2 返回string
如果controller方法返回string ,
(1)表示返回逻辑视图名
真正视图(jsp路径)= 前缀+逻辑视图名+后缀;
例如:
@RequestMapping("testString") public String testString(Model model) { try { FClientCustom custom = fcService.findClientById(1); model.addAttribute("custom", custom); } catch (Exception e) { model.addAttribute("error", "出错了! " + e.getMessage()); } return "/clientedit.jsp"; }
特点:浏览器地址栏的url会变化,修改提交的request数据无法传到重定向的地址,因为重定向的地址后重新进行了request;
使用: return "redirect:clientsList.action"
例如:
@RequestMapping("testString") public String testString(Model model) { try { FClientCustom custom = fcService.findClientById(1); model.addAttribute("custom", custom); } catch (Exception e) { model.addAttribute("error", "出错了! " + e.getMessage()); } return "redirect:clientedit.jsp"; }
(3)forward 页面转发
使用: return "forward:该handler下的某个action" ;
例如:
@RequestMapping("testString") public String testString(Model model) { try { FClientCustom custom = fcService.findClientById(1); model.addAttribute("custom", custom); } catch (Exception e) { model.addAttribute("error", "出错了! " + e.getMessage()); } return "forward:clientedit.jsp"; }
3.3 返回void
在controller方法形参上可以定义request和response,使用request或response指定响应结果;
(1)使用request转向页面,如下:
request.gerResquestDispatcher(“页面路径”).forword(request,response);
(2)使用response进行页面重定向
response.sendRedirect("url")
(3)可以通过response指定响应结果,例如响应json数据
response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json字符串");
例如:
@RequestMapping("testRequest") public void testRequest(HttpServletRequest request,HttpServletResponse response) { try { int id = Integer.valueOf(request.getParameter("id")); FClientCustom custom = fcService.findClientById(id); request.setAttribute("custom", custom); request.getRequestDispatcher("/clientedit.jsp").forward(request, response); } catch (Exception e) { request.setAttribute("error","出错了 ! "+e.getMessage()); try { request.getRequestDispatcher("/error.jsp").forward(request, response); } catch (Exception e1) { e1.printStackTrace(); } } }
从客户端请求的key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上,springmvc中,接受页面提交的数据是通过方法形参来接收的,而不是在controller类定义成员变接收;处理器适配器调用springmvc提供参数绑定组件将key/value数据转成controller方法的形参;
参数绑定组件:
早期:使用PropertyEditor,将字符串转成java对象;
后期:使用converter进行任意类型转换;
spring提供了很多converter转换器,在特殊情况下,我们需要自定义converter,比如日期的converter转换器;
4.1 默认支持类型
直接在controller方法形参上定义下边类型对象,就可以使用这些类型,直接绑定;
(1)HttpServletRequest : 通过request对象获取请求信息;
(2)HttpServletResponse : 通过response处理响应信息;
例如:
@RequestMapping("testRequest") public void testRequest(HttpServletRequest request,HttpServletResponse response) { try { int id = Integer.valueOf(request.getParameter("id")); FClientCustom custom = fcService.findClientById(id); request.setAttribute("custom", custom); request.getRequestDispatcher("/clientedit.jsp").forward(request, response); } catch (Exception e) { request.setAttribute("error","出错了 ! "+e.getMessage()); try { request.getRequestDispatcher("/error.jsp").forward(request, response); } catch (Exception e1) { e1.printStackTrace(); } } }
@RequestMapping("testString") public String testString(Model model) { try { FClientCustom custom = fcService.findClientById(1); model.addAttribute("custom", custom); } catch (Exception e) { model.addAttribute("error", "出错了! " + e.getMessage()); } return "forward:clientedit.jsp"; }
4.2 简单类型
通过@RequestParam 对简单类型的参数进行绑定;如果不使用@RequestParam ,要求request传入的参数名称和controller方法的形参名称一致,方可绑定成功;如果使用@RequestParam,不用限制request传入参数名称和controller方法的形参名称一致;
例如:
/** * 设置 @ReqeustParam() * @param t_id * @return */ @RequestMapping(value = "/editClientIfoTwo", method = { RequestMethod.POST, RequestMethod.GET }) public ModelAndView editClientIfoTwo(@RequestParam(value="id") Integer t_id) { // 模拟固定的id值,修改id为1的客户信息 ModelAndView view = new ModelAndView(); try { FClientCustom custom = fcService.findClientById(t_id); view.addObject("custom", custom); view.setViewName("/clientedit.jsp"); } catch (Exception e) { view.addObject("error", e.getMessage()); view.setViewName("error.jsp"); } return view; }
设置required属性为true,则指定参数必须要传入;
设置defaultValue可以设置默认值,如果id参数没有传入,将默认值和形参绑定;
例如:
@RequestMapping(value = "/editClientIfoThree", method = { RequestMethod.POST, RequestMethod.GET }) public ModelAndView editClientIfoThree(@RequestParam(value="id",required=true) Integer t_id) { // 模拟固定的id值,修改id为1的客户信息 ModelAndView view = new ModelAndView(); try { FClientCustom custom = fcService.findClientById(t_id); view.addObject("custom", custom); view.setViewName("/clientedit.jsp"); } catch (Exception e) { view.addObject("error", e.getMessage()); view.setViewName("error.jsp"); } return view; }
简单类型还有:int , String , double ,boolean
4.3 pojo绑定
页面中input的name值和controller的pojo形参中的属性名称一致,将页面中的数据绑定到pojo中;
例如:
jsp中的表单中的input的name值和pojo的属性名一直:
<input type="text" name="client_certificate_no" value="${custom.client_certificate_no}">
private String client_certificate_no;
首先我们使用的SpringMvc加载驱动用的是注解驱动的方式实现 :
<mvc:annotation-driven ></mvc:annotation-driven>
xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
例如:日期格式转换,将view中的日期字符串转换成我们pojo中data属性的类型;
/** * 自定义参数类型,实现Converter接口 * TODO : 将日期字符串转为java.util.date类型 * 作者:原明卓 * 时间:2016年1月6日 下午4:30:46 * 工程:SpringMvcMybatis1Demo */ public class FormatDateConverter implements Converter<String,Date>{ @Override public Date convert(String source) { SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { return format.parse(source); } catch (ParseException e) { e.printStackTrace(); } return null; } }
(2)第二步 : 配置转换器 conversionService
使用的是 :org.springframework.format.support.FormattingConversionServiceFactoryBean ;
例如:
<!-- 自定义类型,转成器 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <!-- 在这里可以定义多个转换 --> <bean class="cn.labelnet.ssm.controller.converter.FormatDateConverter"></bean> </list> </property> </bean>
在注解驱动中添加 :
<!-- 配置自定义参数映射 --> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
日期格式为了规范化,我们在input表单中添加 pattern属性 :
<input type="text" name="born_date" value="<fmt:formatDate value="${custom.born_date}" pattern="yyyy-MM-dd HH:mm:ss" />">
当然,在jsp中,需要引入两个tablib :
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
SpringMvc完整示例 :注解驱动方式加载
<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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 配置Handler:扫描的方式 --> <context:component-scan base-package="cn.labelnet.ssm.controller"></context:component-scan> <!-- 注解映射器 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> 注解适配器 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean> --> <!-- 使用Mvc:annotation-driven代替上面的注解映射器和适配器 mvc:annotation-driver默认加载很多的参数绑定方法; 那样就不用配置上班的requestMappingHandlerMapping和RequestMappingHandlerAdapter了 推荐使用;<mvc:annotation-driven></mvc:annotation-driven> --> <!-- 配置自定义参数映射 --> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" /> <!-- 自定义类型,转成器 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <!-- 在这里可以定义多个转换 --> <bean class="cn.labelnet.ssm.controller.converter.FormatDateConverter"></bean> </list> </property> </bean> </beans>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'clientedit.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h1>修改客户信息</h1> <form action="${pageContext.request.contextPath}/clients/editClientUpdate.action" method="post" style="width: 80%;"> <table align="center"> <tr> <td>姓名 :</td> <td> <input type="hidden" name="id" value="${custom.id}"> <input type="text" name="username" value="${custom.username}"></td> </tr> <tr> <td>客户代码 :</td> <td><input type="text" name="client_certificate_no" value="${custom.client_certificate_no}"></td> </tr> <tr> <td>生日 :</td> <td><input type="text" name="born_date" value="<fmt:formatDate value="${custom.born_date}" pattern="yyyy-MM-dd HH:mm:ss" />"></td> </tr> <tr> <td>家庭住址:</td> <td><input type="text" name="family_register_address" value="${custom.family_register_address}"></td> </tr> <tr> <td>现居住地 :</td> <td><input type="text" name="now_address" value="${custom.now_address}"></td> </tr> <tr> <td>联系方式 :</td> <td><input type="text" name="contact_mode" value="${custom.contact_mode}"></td> </tr> <tr> <td>紧急联系方式 :</td> <td><input type="text" name="urgency_contact_mode" value="${custom.urgency_contact_mode}"></td> </tr> <%-- <tr> <td>注册日期 :</td> <td><input type="text" readonly="readonly" name="create_date" value="${custom.create_date}"></td> </tr> --%> <tr> <td> <input type="submit" value="提交修改"> </td> </tr> </table> </form> </body> </html>
6.1 post乱码
在web.xml中配置过滤器;
使用的是:org.springframework.web.filter.CharacterEncodingFilter
<!-- 过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(1) 修改tomcat配置文件添加编码与工程编码一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" ...../>
(2) 或者对参数进行重新编码:
String uname=new String(request.getParamter("uname").getBytes("ISO8859-1"),"UTF-8");
1) springmvc基于方法开发的,struct2基于类开发的
2) springmvc将url和controller方法映射,映射成功后将springmvc生成一个handler对象,对象中包括了一个method,方法执行结束,形参数据销毁;
3) springmvc可以进行单例开发,并且建议使用单例开发;
structs2通过类的成员变量接收参数,无法使用单例,只能使用多例;
4) springmvc的controller开发类似与service开发;
5) 经过实际测试,struts2速度慢,在于使用struts标签,建议使用jstl;
http://download.csdn.net/detail/lablenet/9393772