体验springmvc
目前比较好的MVC框架,老牌的有Struts1.x、Webwork (Struts2)。新的MVC框架有Spring MVC、Tapestry、JSF等。这些大多是著名团队的作品。这些框架都提供了较好的层次分隔能力。在实现良好的MVC 分隔的基础上,通过提供一些现成的辅助类库,同时也促进了生产效率的提高。
Spring MVC工作原理
- Dispatcher Servlet分发器
- Handler Mapping 处理器映射
- Controller 控制器
- ModelAndView
- ViewResolver 视图解析器
Java MVC 框架性能测试
- 测试结果:
Spring-framework
Spring框架是业务层框架,核心组件是容器 它是管理bean的,广义上讲任何一个javaBean它都管理,实例化对象 两大概念:IOC、AOP
IOC : (Inversion of Control)
它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。它是获得依赖对象的方式。
好莱坞原则,即“不要打电话过来,我们会打给你”。
AOP:( Aspect-Oriented Programming) 面向方面编程
可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。
当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
SpringMVC
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
面试要点:Struts1、Struts2和springmvc比较
- 都是web层框架。
- Struts1是基于servlet;Struts2是基于filter;springmvc是基于servlet 。
- Struts1的action是单例模式,线程不安全的;Struts2 action是原型模式 prototype,每次访问对象都会创建新的实例,保证线程安全性;springmvc controller是单例模式,整个程序只有一个对象实例。Spring的安全性是通过绑定threadlocal实现。
- Struts1使用JSTL EL表达式,但是对集合和索引属性的支持很弱。Struts2采用 OGNL。
- struts2是类级别的拦截, 一个类对应一个request上下文,springmvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应。
- Strust1中通常以action访问时.do,struts2、spring mvc 都是以.action做结尾。
- spring3 mvc可以认为已经100%零配置了。
开发步骤:
- 新建web project
-
引入jar包
spring-aop-3.2.2.jar 面向切片编程 spring-aspects-3.2.2.jar 提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中 spring-beans-3.2.2.jar 核心。访问配置文件、创建和管理bean 以及进行IoC/DI操作相关的所有类。 spring-context-3.2.2.jar为Spring 核心提供了大量扩展。 spring-context-support-3.2.2.jar spring-core-3.2.2.jar Spring 框架基本的核心工具类。外部依赖Commons Logging 。 spring-expression-3.2.2.jar 配置对象的注入,它便是SpEL (Spring Expression Language) spring-web-3.2.2.jar Web 应用开发时,用到Spring 框架时所需的核心类 spring-webmvc-3.2.2.jar Spring MVC 框架相关的所有类。包括框架的Servlets,Web MVC框架,控制器和视图支持。 注意spring3.0的包名是 org.spingframework.web.servlet-3.1.0 RELEASE.jar com.springsource.org.apache.commons.logging-1.1.1.jar 日志 com.springsource.org.aopalliance-1.0.0.jar AOP联盟的API包,里面包含了针对面向切面的接口。
-
配置分发器servlet DispatchServlet
<servlet> <servlet-name>action</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
-
创建控制器类
public class HomeController extends AbstractController { protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("HomeController..."); return new ModelAndView("index"); } }
-
配置beans,创建spring配置文件 /WEB-INF/action-servlet.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- 控制器 --> <bean name="/home.action" class="cn.albin.springmvc.controller.HomeController"/> <!-- 内部资源视图解析器 --> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsps/"/> <!-- 前缀 --> <property name="suffix" value=".jsp"/> <!-- 后缀 --> </bean> </beans>
-
创建jsp文件
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>index.jsp</title> </head> <body> This is my JSP page. <br> </body> </html>
-
发布、测试
SpringMVC 入门
web.xml 配置
<!-- 注册springmvc核心控制器 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通知DispatcherServlet去指定的目录下加载springmvc.xml配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!-- 注册spring提供的针对POST请求的中文乱码问题 -->
<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>
springmvc.xml配置文件(src 目录)
视图解析器【解析视图逻辑名对应的真实路径】【配置可省】InternalResourceViewResolver
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
">
<!-- 注册Action(必须配置) -->
<bean name="/hello.action" class="cn.albin.javaee.springmvc.app07.HelloAction"></bean>
<!--
如果Action中书写的是视图逻辑名称,那么视图解析器就必须配置
如果Action中书写的是视图真实名称,那么视图解析器就可选配置
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 路径前缀 -->
<property name="prefix" value="/jsp/"/>
<!-- 路径后缀 -->
<property name="suffix" value=".jsp"/>
<!-- 前缀+视图逻辑名+后缀=真实路径 -->
</bean>
</beans>
控制层
/**
* 单例
* 控制器Action
* 处理器Action
* @author albin
*/
public class HelloAction implements Controller{
/**
* 业务方法
*/
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message","这是我的第二个springmvc应用程序,视图使用逻辑名");
//原来封装视图的真实路径
//modelAndView.setViewName("/jsp/success.jsp");
//现在封装视图的逻辑名称
modelAndView.setViewName("success");
return modelAndView;
}
}
初识原理
映射器Mapping【什么样的请求交给Action】【配置可省】BeanNameUrlHandlerMapping
-
java
/** * 控制器 * @author 谢斌 */ public class UserAction implements Controller{ public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception { System.out.println("操作用户"); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("message","操作用户成功"); modelAndView.setViewName("success"); return modelAndView; } }
-
xml
<!-- 注册Action --> <bean name="/add.action" class="cn.albin.javaee.springmvc.app08.UserAction"></bean> <!-- 映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- 适配器 --> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
映射器SimpleUrlHandlerMapping适合】于将多个请求,映射到同一个Action
<!-- 注册Action -->
<bean id="userActionID" class="cn.albin.javaee.springmvc.app08.UserAction"></bean>
<!-- 注册映射器
【适合】于将多个请求,映射到同一个Action
-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- key表示请求路径 -->
<prop key="/update.action">userActionID</prop>
<prop key="/delete.action">userActionID</prop>
<prop key="/find.action">userActionID</prop>
</props>
</property>
</bean>
适配器Adapter【Action实现什么接口】【配置可省】SimpleControllerHandlerAdapter
-
java
/** * 控制器是实现Controller接口的类 * @author 谢斌 */ public class EmpAction implements Controller{ public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception { ModelAndView modelAndView = new ModelAndView(); //设置编码方式 request.setCharacterEncoding("UTF-8"); //获取员工姓名 String username = request.getParameter("username"); //显示 System.out.println("员工姓名:" + username); //将员工姓名封装到ModelAndView对象中去 modelAndView.addObject("message",username); //将真实路径名封装到ModelAndView对象中去 modelAndView.setViewName("/jsp/success.jsp"); return modelAndView; } }
-
xml
<!-- EmpAction处理类 --> <bean name="/add.action" class="cn.albin.javaee.springmvc.app09.EmpAction"></bean> <!-- 映射器(省) --> <!-- 适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- 视图解析器(省) -->
注解快速入门
-
java
/** * 单例 * 控制器(程序员) */ @Controller public class HelloAction{ public HelloAction(){ System.out.println("HelloAction()::" + this.hashCode()); } /** * 业务方法 * 只要是/hello.action的请求,都交由HelloAction对象中的hello()方法去处理 */ @RequestMapping(value="/hello.action") public String hello(Model model) throws Exception{ System.out.println("HelloAction::hello()"); model.addAttribute("message","你好"); return "success"; } /** * 业务方法 * 只要是/bye.action的请求,都交由HelloAction对象中的bye()方法去处理 */ @RequestMapping(value="/bye.action") public String bye(Model model) throws Exception{ System.out.println("HelloAction::hello()"); model.addAttribute("message","再见"); return "success"; } }
-
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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <!-- Action,让springioc容器去扫描带@Controller的类 --> <context:component-scan base-package="cn.albin.javaee.springmvc.app14"/> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
一个Action中,写多个类似的业务控制方法
-
控制器
/** * 控制器 * @author albin */ @Controller @RequestMapping(value="/user") public class UserAction { /** * 用户注册 */ @RequestMapping(value="/register") public String registerMethod(Model model) throws Exception{ model.addAttribute("message","员工注册成功"); return "/jsp/success.jsp"; } /** * 用户登录 */ @RequestMapping(value="/login") public String loginMethod(Model model) throws Exception{ model.addAttribute("message","员工登录成功"); return "/jsp/success.jsp"; }
-
spring.xml
<!-- Action,让springioc容器去扫描带@Controller的类 --> <context:component-scan base-package="cn.albin.javaee.springmvc.app15"/> <!-- 映射器(省) --> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> </bean>
在业务控制方法中写入普通变量收集参数
限定某个业务控制方法,只允许GET或POST请求方式访问
-
控制器
/** * 控制器 * @author albin */ @Controller @RequestMapping(value="/user") public class UserAction { /** * 用户注册,只能接收POST请求 */ @RequestMapping(method=RequestMethod.POST,value="/register") public String registerMethod(Model model,String username,String salary) throws Exception{ System.out.println("用户注册-->" + username + ":" + salary); model.addAttribute("message","员工注册成功"); return "/jsp/success.jsp"; } /** * 用户登录,即能接收POST请求,又能接收GET请求 */ @RequestMapping(value="/login") public String loginMethod(Model model,String username) throws Exception{ System.out.println("用户登录-->" + username); model.addAttribute("message","员工登录成功"); return "/jsp/success.jsp"; } }
在业务控制方法中写入HttpServletRequest,HttpServletResponse,Model等传统web参数
-
控制器
/** * 控制器 * @author albin */ @Controller @RequestMapping(value="/user") public class UserAction { /** * 用户注册,只能接收POST请求 */ @RequestMapping(method=RequestMethod.POST,value="/register") public String registerMethod(HttpServletRequest request,HttpServletResponse response) throws Exception{ //获取用户名和薪水 String username = request.getParameter("username"); String salary = request.getParameter("salary"); System.out.println("用户注册-->" + username + ":" + salary); //绑定到session域对象中 request.getSession().setAttribute("username",username); request.getSession().setAttribute("salary",salary); //重定向/jsp/success.jsp页面 //response.sendRedirect(request.getContextPath()+"/jsp/success.jsp"); //转发/jsp/ok.jsp页面 request.getRequestDispatcher("/jsp/ok.jsp").forward(request,response); //转发(提倡) return "/jsp/success.jsp"; } }
在业务控制方法中写入模型变量收集参数,且使用@InitBind来解决字符串转日期类型
-
控制器
/** * 控制器 * @author albin */ @Controller @RequestMapping(value="/user") public class UserAction { /** * 自定义类型转换器 */ @InitBinder public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception { binder.registerCustomEditor( Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),true)); } /** * 用户注册,只能接收POST请求 */ @RequestMapping(method=RequestMethod.POST,value="/register") public String registerMethod(User user,Model model) throws Exception{ System.out.println("用户注册:" + user.toString()); //将user绑定到model对象中 model.addAttribute("user",user); //转发到success.jsp页面 return "/jsp/success.jsp"; } }
在业务控制方法中写入User,Admin多个模型收集参数
-
控制器
/** * 控制器 * @author albin */ @Controller @RequestMapping(value="/person") public class PersonAction { @InitBinder public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception { binder.registerCustomEditor( Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true)); } /** * 业务方法 */ @RequestMapping(value="/register") public String registerMethod(Bean bean,Model model) throws Exception{ System.out.println("普通用户:" + bean.getUser()); System.out.println("管理员:" + bean.getAdmin()); //将user和admin都绑定到Model model.addAttribute("user",bean.getUser()); model.addAttribute("admin",bean.getAdmin()); //转发 return "/02_person.jsp"; } }
在业务控制方法中收集数组参数
@Controller
@RequestMapping(value="/emp")
public class EmpAction {
@RequestMapping(value="/deleteAll",method=RequestMethod.POST)
public String deleteAll(Model model,int[] ids) throws Exception{
System.out.println("需要删除的员工编号分别是:");
for(int id : ids){
System.out.print(id+" ");
}
model.addAttribute("message","批量删除员工成功");
return "/jsp/ok.jsp";
}
}
在业务控制方法中收集List参数
-
控制器
@Controller @RequestMapping(value="/emp") public class EmpAction { /** * 批量添加员工 */ @RequestMapping(value="/addAll",method=RequestMethod.POST) public String addAll(Model model,Bean bean) throws Exception{ for(Emp emp:bean.getEmpList()){ System.out.println(emp.getUsername()+":"+emp.getSalary()); } model.addAttribute("message","批量增加员工成功"); return "/jsp/ok.jsp"; } }
结果的转发和重定向
-
控制器
@Controller @RequestMapping(value="/emp") public class EmpAction { @RequestMapping(value="/find") public String findEmpById(int id,Model model) throws Exception{ System.out.println("查询"+id+"号员工信息"); //转发到EmpAction的另一个方法中去,即再次发送请求 return "forward:/emp/update.action"; //重定向到EmpAction的另一个方法中去,即再次发送请求 //return "redirect:/emp/update.action?id=" + id; } @RequestMapping(value="/update") public String updateEmpById(int id,Model model) throws Exception{ System.out.println("更新" + id +"号员工信息"); model.addAttribute("message","更新员工信息成功"); return "/jsp/ok.jsp"; } }
JSON 使用
1)导入jackson-core-asl-1.9.11.jar和jackson-mapper-asl-1.9.11.jar
3)在spring.xml配置文件中编写如下代码:
<!--
1)导入jackson-core-asl-1.9.11.jar和jackson-mapper-asl-1.9.11.jar
2)在业务方法的返回值和权限之间使用@ResponseBody注解表示返回值对象需要转成JSON文本
3)在spring.xml配置文件中编写如下代码:
-->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
-
案例
@Controller @RequestMapping(value="/emp") public class EmpAction { /** * @ResponseBody Emp 表示让springmvc将Emp对象转成json文本 */ @RequestMapping(value="/bean2json") public @ResponseBody Emp bean2json() throws Exception{ //创建Emp对象 Emp emp = new Emp(); emp.setId(1); emp.setUsername("哈哈"); emp.setSalary(7000D); emp.setHiredate(new Date()); return emp; } @RequestMapping(value="/listbean2json") public @ResponseBody List<Emp> listbean2json() throws Exception{ //创建List对象 List<Emp> empList = new ArrayList<Emp>(); //向List对象中添加三个Emp对象 empList.add(new Emp(1,"哈哈",7000D,new Date())); empList.add(new Emp(2,"呵呵",8000D,new Date())); empList.add(new Emp(3,"嘻嘻",9000D,new Date())); //返回需要转JSON文本的对象 return empList; } @RequestMapping(value="/map2json") public @ResponseBody Map<String,Object> map2json() throws Exception{ //创建List对象 List<Emp> empList = new ArrayList<Emp>(); //向List对象中添加三个Emp对象 empList.add(new Emp(1,"哈哈",7000D,new Date())); empList.add(new Emp(2,"呵呵",8000D,new Date())); empList.add(new Emp(3,"嘻嘻",9000D,new Date())); //创建Map对象 Map<String,Object> map = new LinkedHashMap<String,Object>(); //向Map对象中绑定二个变量 map.put("total",empList.size()); map.put("rows",empList); //返回需要转JSON文本的对象 return map; } }
* jsp
<body>
<input type="button" value="Emp转JSON"/><p>
<input type="button" value="List<Emp>转JSON"/><p>
<input type="button" value="Map<String,Object>转JSON"/><p>
<!-- Map<String,Object>转JSON -->
<script type="text/javascript">
$(":button:last").click(function(){
var url = "${pageContext.request.contextPath}/emp/map2json.action";
var sendData = null;
$.post(url,sendData,function(backData,textStaut,ajax){
alert(ajax.responseText);
});
});
</script>
<!-- List<Emp>转JSON -->
<script type="text/javascript">
$(":button:eq(1)").click(function(){
var url = "${pageContext.request.contextPath}/emp/listbean2json.action";
var sendData = null;
$.post(url,sendData,function(backData,textStaut,ajax){
alert(ajax.responseText);
});
});
</script>
<!-- Emp转JSON -->
<script type="text/javascript">
$(":button:first").click(function(){
var url = "${pageContext.request.contextPath}/emp/bean2json.action";
var sendData = null;
$.post(url,sendData,function(backData,textStaut,ajax){
//alert(ajax.responseText);
var hiredate = backData.hiredate;
var date = new Date(hiredate);
alert(date.getFullYear()+"年"+(date.getMonth()+1)+"月"+(date.getDate())+"日");
});
});
</script>
</body>