java mvc框架入门,Spring MVC 框架入门学习
1.Spring web mvc介绍
Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:
2.Web mvc
用户发起request请求至控制器(Controller)
控制接收用户请求的数据,委托给模型进行处理
控制器通过模型(Model)处理数据并得到处理结果
模型通常是指业务逻辑
控制器将模型数据在视图(View)中展示
web中模型无法将数据直接在视图上显示,需要通过控制器完成。如果在C/S应用中模型是可以将数据在视图中展示的。
控制器将视图response响应给用户
通过视图展示给用户要的数据或处理结果。
3.Spring web mvc 架构
架构图
流程
用户发送请求至前端控制器DispatcherServlet.
DispatcherServlet收到请求调用HandlerMapping处理器映射器.
处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet.
DispatcherServlet调用HandlerAdapter处理器适配器.
HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器).
Controller执行完成返回ModelAndView.
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet.
DispatcherServlet将ModelAndView传给ViewReslover视图解析器.
ViewReslover解析后返回具体View.
DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
DispatcherServlet响应用户
组件说明:
++以下组件通常使用框架提供实现:++
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。
++下边两个组件通常情况下需要开发++:
Handler:处理器,即后端控制器用controller表示。
View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。
4.开发环境准备
本教程使用Eclipse+tomcat7开发
详细参考“Eclipse开发环境配置-indigo.docx”文档
5.第一个springmvc工程
第一步:建立一个Web项目
在eclipse下创建动态web工程springmvc_01。
第二步:导入spring3.1.4的jar包
第三步:前端控制器配置
在WEB-INF\web.xml中配置前端控制器,
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-servlet.xml
// 表示servlet随服务启动
1
springmvc
// 以.action结尾的请求交给DispatcherServlet处理
*.action
load-on-startup:表示servlet随服务启动;
url-pattern:*.action的请交给DispatcherServlet处理。
contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加载WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml。
第四步:springmvc配置文件
Springmvc默认加载WEB-INF/[前端控制器的名字]-servlet.xml,也可以在前端控制器定义处指定加载的配置文件,如下:
contextConfigLocation
classpath:springmvc-servlet.xml
如上代码,通过contextConfigLocation加载classpath下的springmvc-servlet.xml配置文件,配置文件名称可以不限定[前端控制器的名字]-servlet.xml。
第五步:配置处理器映射器
在springmvc-servlet.xml文件配置如下:
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“
xmlns:aop=”http://www.springframework.org/schema/aop“ xmlns:tx=”http://www.springframework.org/schema/tx“
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd “>
BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。
第六步:配置处理器适配器
在springmvc-servlet.xml文件配置如下:
SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为Springmvc的后端控制器。
第七步:配置视图解析器
在springmvc-servlet.xml文件配置如下:
InternalResourceViewResolver:支持JSP视图解析.
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath必须包含jstl的相关jar包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址“WEB-INF/jsp/hello.jsp”
第八步:后端控制器开发
后端控制器即controller,也有称为action。
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.web.servlet.ModelAndView;
importorg.springframework.web.servlet.mvc.Controller;
public class HelloWorldController implements Controller {
@Override
Public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
ModelAndView mv = new ModelAndView();
// 添加模型数据
mv.addObject(“message”, “Hello World!”);
// 设置逻辑视图名,最终视图地址=前缀+逻辑视图名+后缀
mv.setViewName(“hello”);
return mv;
}
}
org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。
ModelAndView:包含了模型数据及逻辑视图名
第九步:后端控制器配置
在springmvc-servlet.xml文件配置如下:
name=”/hello.action” :前边配置的BeanNameUrlHandlerMapping,表示如过请求的URL为“上下文/hello.action”,则将会交给该Bean进行处理。
第十步:视图开发
创建/WEB-INF/jsp/hello.jsp视图页面:
pageEncoding=”UTF-8”%>
第一个程序
${message}
${message}:表示显示由HelloWorldController处理器传过来的模型数据。
第十一步:部署在tomcat测试
总结:
主要进行如下操作:
前端控制器DispatcherServlet配置
加载springmvc的配置文件
HandlerMapping配置
HandlerAdapter配置
ViewResolver配置
前缀和后缀
后端控制器编写
后端控制器配置
视图编写
从上边的步骤可以看出,通常情况下我们只需要编写后端控制器和视图。
6.HandlerMapping处理器映射器
HandlerMapping 给前端控制器返回一个HandlerExecutionChain 对象(包含一个Handler (后端控制器)对象、多个HandlerInterceptor 拦截器)对象。
BeanNameUrlHandlerMapping
beanName Url映射器
将后端控制器的bean name作为请求的url。
SimpleUrlHandlerMapping
hello_controller
hello_controller
可定义多个url映射至一个后端控制器,hello_controller为后端控制器bean的id。
7.HandlerAdapter处理器适配器
HandlerAdapter会把后端控制器包装为一个适配器,支持多种类型的控制器开发,这里使用了适配器设计模式。
SimpleControllerHandlerAdapter
简单控制器处理器适配器.
所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean作为Springmvc的后端控制器。
适配器配置如下:
HttpRequestHandlerAdapter
HTTP请求处理器适配器.
HTTP请求处理器适配器将http请求封装成HttpServletResquest和HttpServletResponse对象,和servlet接口类似。
适配器配置如下:
Controller实现如下:
publicclass HelloWorldController2 implements HttpRequestHandler {
@Override
publicvoid handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
request.setAttribute(“message”, “HelloWorld!”);
request.getRequestDispatcher(“/WEB-INF/jsp/hello.jsp”).forward(request, response);
// 也可以自定义响应内容
//response.setCharacterEncoding(“utf-8”);
//response.getWriter().write(“HelloWorld!”);
}
}
从上边可以看出此适配器器的controller方法没有返回ModelAndView,可通过response修改定义响应内容。
8.Controller控制器
AbstractCommandController(命令控制器)
该控制器能把请求参数封装到一个命令对象(模型对象)中。
public class MyCommandController extends AbstractCommandController {
/**
* 通过构造函数设置命令对象
*/
public MyCommandController(){
this.setCommandClass(Student.class);
this.setCommandName(“student”);//不是必须设置
}
@Override
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
Student student = (Student)command;
System.out.println(student);
Return null;
}
/**
* 字符串转换为日期属性编辑器
*/
@Override
Protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(“yyyy-MM-dd”),true));
}
}
publicclass Student {
public Student() {
}
public Student(String name) {
this.name = name;
}
private String name;//姓名
private Integer age;//年龄
private Date birthday;//生日
private String address;//地址
….get/set方法省略
Controller配置;
使用命令控制器完成查询列表及表单提交
代码略
9.问题解决
日期格式化
在controller注册属性编辑器:
/**
* 注册属性编辑器(字符串转换为日期)
*/
@InitBinder
public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(“yyyy-MM-dd”),true));
}
Post时中文乱码
在web.xml中加入:
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
CharacterEncodingFilter
/*
以上可以解决post请求乱码问题。
对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
另外一种方法对参数进行重新编码:
String userName new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),”utf-8”)
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
10.注解开发
第一个例子
创建工程的步骤同第一个springmvc工程,注解开发需要修改handlermapper和handlMapperAdapter,如下:
在springmvc-servlet.xml中配置:
注解映射器和注解适配器可以使用 代替。
默认注册了注解映射器和注解适配器等bean。
HelloWorldController编写:
@Controller
publicclass HelloWorldController {
@RequestMapping(value=”/hello”)
public String hello(Model model)throws Exception{
model.addAttribute(“message”, “HelloWorld!”);
return”hello”;
}
}
注解描述:
@Controller:用于标识是处理器类
@RequestMapping:请求到处理器功能方法的映射规则
Controller配置
在springmvc-servlet.xml中配置定义的controller:
组件扫描
扫描 @component 、@controller、@service、@repository 的注解
注意:如果使用组件扫描则controller不需要在springmvc-servlet.xml中配置
11.与struts2不同
springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
springmvc是基于方法开发,请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
注意:
不要在action类中定义方法所用到的变量,变量要定义到方法体中。因为方法是在栈内存中,不会导致线程问题。
12.@Controller
标识该类为控制器类,@controller、@service、@repository 分别对应了web应用三层架构的组件即控制器、服务接口、数据访问接口。
13.@RequestMapping
URL路径映射
@RequestMapping(value=”/user”)或@RequestMapping(“/user”)
根路径+子路径
根路径:
@RequestMapping 放在类名上边,如下:
@Controller
@RequestMapping(“/user”)
子路径:
@RequestMapping 放在方法名上边,如下:
@RequestMapping(“/useradd”)
public String useradd(….
URI 模板模式映射
@RequestMapping(value=”/useredit/{userId}“):{×××}占位符,请求的URL可以是“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable 获取{×××}中的×××变量。
@RequestMapping(“/useredit/{userid}“)
public String useredit(@PathVariable String userid,Model model) throws Exception{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute(“userid”, userid);
return”/user/useredit”;
}
实现restFul,所有的url都是一个资源的链接,有利于搜索引擎对网址收录。
多个占位符:
@RequestMapping(“/useredit/{groupid}/{userid}“)
public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute(“groupid”, groupid);
model.addAttribute(“userid”, userid);
return”/user/useredit”;
}
页面:
修改
请求方法限定
限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过Post访问则报错:
HTTP Status 405 - Request method ‘POST’ not supported
例如:
@RequestMapping(value=”/useredit/{userid}“,method=RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
如果通过Post访问则报错:
HTTP Status 405 - Request method ‘GET’ not supported
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
14.请求数据绑定(重点)
Controller方法通过形参接收页面传递的参数。
如下:
@RequestMapping(“/userlist”)
public String userlist(
HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model
)
默认支持的参数类型
HttpServletRequest
通过request对象获取请求信息
HttpServletResponse
通过response处理响应信息
HttpSession
通过session对象得到session中存放的对象
session.setAttribute(“userinfo”, student);
session.invalidate(); // 使session失效
Model
通过model向页面传递数据,如下:
model.addAttribute(“user”, new User(“李四”));
页面通过${user.XXXX}获取user对象的属性值。
命令/表单对象
自动将请求参数绑定到功能处理方法的命令/表单对象上。
Controller方法通过形参接收命令/表单对象。
Java基本数据类型
布尔型:
页面如下:
用户状态:
整型
例子略
单精度/双精度
例子略
日期型需要添加属性编辑器:
@InitBinder
Public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(“yyyy-MM-dd”),true));
例子略
Pojo对象
页面上以pojo对象中属性名称命名:
将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
页面定义如下;
Contrller方法定义如下:
public String useraddsubmit(Model model,User user)throws Exception{
System.out.println(user);
}
页面上以pojo对象名点属性名命名:
如果采用类似struts中对象.属性的方式命名,需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
包装对象定义如下:
Public class UserVo {
private User user;
public User getUser() {
return user;
}
Public void setUser(User user) {
this.user = user;
}
}
页面定义:
Controller方法定义如下:
public String useraddsubmit(Model model,UserVo userVo)throws Exception{
System.out.println(userVo.getUser());
}
字符串数组
使用情景:页面提交批量数据以数组接受
页面定义如下:
页面选中多个checkbox向controller方法传递
${student.id}${student.name}
传递到controller方法中的格式是:001,002,003
Controller方法中可以用String[]接收,定义如下:
@RequestMapping(“/deleteStudent”)
public String deleteStudent(String[] deleteids)throws Exception {
return “editStudentSubmit”;
}
List
List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。
List中对象:
成绩对象
public class StudentScore {
private String coursename;//课程名称
private Float score;//成绩
public String getCoursename() {
returncoursename;
}
Public void setCoursename(String coursename) {
this.coursename = coursename;
}
public Float getScore() {
returnscore;
}
Public void setScore(Float score) {
this.score = score;
}
}
Public class UserVo {
Private List scores;//成绩
//get/set方法..
}
包装类中定义List对象,并添加get/set方法如下:
private List scores;//成绩
页面:
课程成绩:
课程名:成绩:
课程名:成绩:
课程名:成绩:
Contrller方法定义如下:
public String useraddsubmit(Model model,UserVo userVo)throws Exception{
System.out.println(userVo.getScores ());
}
Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:
Public class UserVo {
private Mapstudentinfo = new HashMap();
//get/set方法..
}
页面定义如下:
学生信息:
姓名:
年龄:
.. .. ..
15.拦截器
定义
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
SpringMVC拦截器是针对mapping配置的拦截器
拦截器定义
实现HandlerInterceptor接口,如下:
Public class HandlerInterceptor1 implements HandlerInterceptor{
/**
* controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
Return false;
}
/**
* controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
Public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
Public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
拦截器配置
针对某种mapping配置拦截器
class=”org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping”>
针对所有mapping配置全局拦截器
正常流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true。
运行流程
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
中断流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2。
运行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:
HandlerInterceptor1..preHandle..
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的ostHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
拦截器应用
用户身份认证
Public class LoginInterceptor implements HandlerInterceptor{
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//如果是登录页面则放行
if(request.getRequestURI().indexOf(“login.action”)>=0){
return true;
}
HttpSession session = request.getSession();
//如果用户已登录也放行
if(session.getAttribute(“user”)!=null){
return true;
}
//用户没有登录挑战到登录页面
request.getRequestDispatcher(“/WEB-INF/jsp/login.jsp”).forward(request, response);
return false;
}
}
还没有评论,来说两句吧...