Spring MVC框架
SpringMVC框架
1、什么是SpringMVC
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。具体更多详细请参考官方文档–>
官方文档(英文):https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html
2、SpringMVC的请求流程
(1)用户发送请求至前端控制器DispatcherServlet
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器)
(6)Handler执行完成返回ModelAndView
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户
总结SpringMVC的工作原理:
- 客户端发送请求到 DispatcherServlet
- DispatcherServlet 查询 handlerMapping 找到处理请求的 Controller
- Controller 调用业务逻辑后,返回 ModelAndView
- DispatcherServlet 查询 ModelAndView,找到指定视图
- 视图将结果返回到客户端
3、SpringMVC的优点
(1)可以支持各种视图技术,而不仅仅局限于JSP
(2)与Spring框架集成(如IoC容器、AOP等)
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)
(4) 支持各种请求资源的映射策略
4、Spring MVC的主要组件
(1)前端控制器 DispatcherServlet(不需要程序员开发)
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
(2)处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的URL来查找Handler
(3)处理器适配器HandlerAdapter
注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以 正确的去执行Handler。
(4)处理器Handler(需要程序员开发)
(5)视图解析器 ViewResolver(不需要程序员开发)
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
(6)视图View(需要程序员开发jsp)
View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
5、SpringMVC重定向与请求转发
(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"
6、SpringMVC怎么和Ajax相互调用
通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :
(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。
7、SpringMVC框架中乱码问题
(1)解决post请求乱码问题:
在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;
<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>
(2)get请求中文参数出现乱码解决方法有两个:
①修改tomcat配置文件添加编码与工程编码一致,如下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
②另外一种方法对参数进行重新编码:
String userName =
new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
注:ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
8、SpringMVC常用注解
@RequestMapping
:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径
@RequestBody
:注解实现接收http请求的json数据,将json转换为java对象
@ResponseBody
:注解实现将conreoller方法返回对象转化为json对象响应给客户
@RequestParm
: 用于把请求中指定名称的参数给控制器中的形参赋值,也可以说起别名
@PathVaribale
: 用于绑定url中的占位符。例如:请求 url 中 /delete/{id},这个**{id}**就是 url 占位符。
@Controller
: 用于定义一个控制器类,但需要交给spring管理并且配上@RequestMapping注解才算SpringMVC
Controller层 ; 注意控制器类也可以使用@RestController
,该注解相当于@ResponseBody +@Controller,表示是表现层,除此之外,一般不用别的注解代替
@Service
:用于标注业务层
@Repository
: 用于注解dao层,在daoImpl类上面注解。
@Component
: 通用注解,当不知道一些类归到哪个层时使用,但是不建议
@Resource
和@Autowired
:
@Autowired
:就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。当Spring找不到bean时会抛出异常,将@Autowired注解的required属性设置为false 不会抛出异常,会显示null;当有多个bean对应时,Spring因为不能判定应该使用哪个bean同样会抛出异常,此时使用@Qualifier(“class-name”)注解,即可指定bean
@Resource
:默认通过name属性去匹配bean,当找不到时再按type去匹配,当指定了name或者type则根据指定的类型去匹配bean,任何一个不匹配豆浆报错
注意:@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了;Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
9、SpringMVC拦截器的实现
有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可:
<!-- 配置SpringMvc的拦截器 -->
<mvc:interceptors>
<!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 -->
<bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean>
<!-- 只针对部分请求拦截 -->
<mvc:interceptor>
<mvc:mapping path="/modelMap.do" />
<bean class="com.zwp.action.MyHandlerInterceptorAdapter" />
</mvc:interceptor>
</mvc:interceptors>
实现HandlerInterceptor接口。接口中提供三个方法。
- preHandle :进入 Handler方法之前执行,用于身份认证、身份授权,比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
- postHandle:进入Handler方法之后,返回modelAndView之前执行,应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
- afterCompletion:执行Handler完成执行此方法,应用场景:统一异常处理,统一日志处理
为了更直观的了解SpringMVC拦截器的实现,我特写个demo,代码如下:
拦截器定义:
注意:com.shsxt.vo.User是一个简单的JavaBean,用于模拟用户登录而用。
package com.shsxt.interceptors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.shsxt.vo.User;
public class LoginInterceptor implements HandlerInterceptor{
/**
* 方法拦截前执行
*/
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
User user= (User) request.getSession().getAttribute("user");
/**
* 判断 uri 是否包含路径
* 包含就放行
*/
if(request.getRequestURI().indexOf("userLogin.do")>-1){
return true;
}
/**
* 判断 session user 是否为空
*/
if(null==user){
response.sendRedirect(request.getContextPath()+"/login.jsp");
return false;
}
return true; //继续执行 action
}
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
System.out.println("Action 执行之后,生成视图之前执行!!");
}
/**
* 在方法执行后进行拦截
*/
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)throws Exception {
System.out.println("方法执行后进行拦截。。释放资源。。。");
}
}
UserController 类:
package com.shsxt.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.shsxt.vo.User;
/**
*
* @author Administrator
* 模拟 用户操作
*/
@Controller
@RequestMapping("/user")
public class UserLoginController {
@RequestMapping("/userLogin")
public ModelAndView userLogin(HttpServletRequest request){
ModelAndView mv=new ModelAndView();
User user=new User();
user.setUserName("sxt");
user.setUserPwd("123456");
request.getSession().setAttribute("user", user);
mv.setViewName("success");
return mv;
}
@RequestMapping("/addUser")
public ModelAndView addUser(){
System.out.println("添加用户记录。。。");
ModelAndView mv=new ModelAndView();
mv.setViewName("success");
return mv;
}
@RequestMapping("/delUser")
public ModelAndView delUser(){
ModelAndView mv=new ModelAndView();
mv.setViewName("success");
return mv;
}
@RequestMapping("/updateUser")
public ModelAndView updateUser(){
ModelAndView mv=new ModelAndView();
mv.setViewName("success");
return mv;
}
}
XML配置:
<!-- 拦截所有请求 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.shsxt.interceptors.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
10、SpringMVC文件上传
① 添加依赖与修改xml配置
<!--pom配置-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<!---------------------------------------->
<!--xml配置-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
②添加控制器
package com.shsxt.controller;
import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class FileController {
@RequestMapping("/uploadFile")
public ModelAndView uploadFile(HttpServletRequest request){
ModelAndView mv=new ModelAndView();
mv.setViewName("result");
MultipartHttpServletRequest mr=(MultipartHttpServletRequest) request;
MultipartFile multipartFile= mr.getFile("file");
String path=request.getSession().getServletContext().getRealPath("upload");
System.out.println(path);
if(null!=multipartFile&&!multipartFile.isEmpty()){
String fileName=multipartFile.getOriginalFilename();
try {
multipartFile.transferTo(new File(path,fileName));
mv.addObject("msg", "文件上传成功!");
} catch (Exception e) {
mv.addObject("msg", "上传失败!");
e.printStackTrace();
}
}
return mv;
}
}
③ 准备前台表单
<form action="uploadFile.do" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit"> 提交</button>
</form>
11、SpringMVC全局异常处理
SpringMVC对于异常处理提供支持,通过SpringMVC提供的全局异常处理机制,能够将所有的异常处理从各种处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。
SpringMVC提供的三种处理异常实现方式:
- 使用SpringMVC提供的简单异常处理器 SimpleMappingExceptionResolver
- 实现Spring的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器
- 使用@ExceptionHandler注解实现异常处理
具体实现代码(仅供参考):
第一种:配置SimpleMappingExceptionResolver对象
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
<property name="defaultErrorView" value="error"></property>
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMapping">
<props>
<prop key="com.shsxt.exception.BusinessException">error</prop>
<prop key="com.shsxt.exception.ParamsException">error</prop>
</props>
</property>
</bean>
**注:**使用此方法进行异常处理,具有集成简单,有良好的扩展性,对已有代码没有入侵性等优点,但该方法仅能够获取到异常信息,若出现异常时,对需要获取异常以外的数据的情况不适用
第二种:实现HandlerExceptionReslover接口(推荐)
public class MyExceptionHandler implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){
Map<String,Object> map=new HashMap<String, Object>();
map.put("ex", ex);
ModelAndView mv=null;
if(ex instanceof ParamsException){
return new ModelAndView("error_param", map);
}
if(ex instanceof BusinessException){
return new ModelAndView("error_business", map);
}
return new ModelAndView("error", map);
}
}
注:使用实现此种异常处理器进行异常处理,比起上一种就是在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。
第三种:页面处理器继承 BaseController
public class BaseController {
@ExceptionHandler
public String exc(HttpServletRequest request,HttpServletResponse response,Exception ex){
request.setAttribute("ex", ex);
if(ex instanceof ParamsException){
return "error_param";
}
if(ex instanceof BusinessException){
return "error_business";
}
return "error";
}
}
注:使用@ExceptionHandler 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BaseController 即可)、不需要附加 Spring 配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据。
未捕获的异常处理
修改 web.xml 文件,增加以下内容:
<!-- 出错页面定义 -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/500.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
上一篇: Activity创建过程
下一篇: GTK+控件简介
推荐阅读