Spring Mvc
一、什么叫MVC?
MVC即Model、View、Controller 即模型、视图、控制器。
MVC要实现的目标是将应用界面与业务逻辑分离,达到解耦。
二、常见MVC框架比较
运行性能上:
Jsp+servlet>strusts1>spring mvc>struts2+freemarker>struts2,ognl,值栈。
开发效率上,基本正好相反。但spring mvc域对象struts2的开发效率差不多。
三、Spring Mvc
1、Spring Mvc是什么?
Spring Mvc是一种基于Java的实现MVC设计模式的请求驱动 类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的是使用请求-响应模型,框架的目的就是帮助我们简化开发。
2、Spring Mvc的请求处理流程
1、首先用户发送请求,请求被Spring Mvc前端控制器(DispatherServlet)捕获;
2、前端控制器(DispatherServlet)对请求URL解析获取请求URI,根据URI,调用HandlerMapping;
3、前端控制器(DispatherServlet)获得返回的HandlerExceptionChain(包括Handler对象以及Handler对象对应的拦截器);
4、DispatherServlet根据获得的HandlerExecutionChain,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法);
5、HandlerAdapter根据请求的Handler适配并执行对应的Handler;
HandlerAdapter(
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据配置,Spring将做一些额外的工作:
HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换成指定的响应信息。
数据转换:对请求消息进行数据转换。如Spring转换成Integer、Double等
数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数据或格式化日期等。
数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中。
)
6、Handler执行完毕,返回一个ModelAndView(即模型和视图)给HandlerAdapter。
7、HandlerAdapter适配器将执行结果ModelAndView返回给前端控制器。
8、前端控制器接收到ModelAndView后,请求对应的视图解析器。
9、视图解析器解析ModelAndView后返回对应View。
10、渲染视图并返回渲染后的视图给前端控制器。
11、最终前端控制器将渲染后的页面响应给用户或客户端。
3、Spring Mvc的优点
1)、支持各种视图技术,不仅仅局限于jsp
2)、与Spring框架集成(如:IoC容器、aop等)
3)、清晰的角色分配
4)、支持各种请求资源的映射策略
4、Spring Mvc的主要组件
前端控制器:DispatcherServlet
映射控制器:handlerMapping
处理器、适配器:controller/handlerAdapter
模型和视图:ModelAndView
视图解析器:viewResolver
5、SpringMvc和struts2的区别
拦截级别:struts2是类级别拦截,SpringMvc是方法级别的拦截
数据独立性:springmvc、struts2的方法之间基本独立。springmvc方法之间不共享变量,struts方法之间共享变量。
拦截机制:struts2有以自己的intercepter机制,springmvc时候独立aop方式,到自己struts2的配置文件比springmvc大
对ajax的支持 : springmvc集成了ajax(用于响应ajax请求返回json),只需要@Resposebody就可以实现,而struts2一般要安装插件或自己写代码才行。
6、servlet和springmvc怎么设定重定向和请求转发
6.1)、servlet :
请求转发:request.getRequestDispacther(“/test.jsp”).forword(request,response);
重定向:response.sendRedirect(“test.jsp”);
6.2)、springmvc:
请求转发:返回值前面加forward
@RequestMapping(“/forward1”)
public String forward1(Model model){
model.addAttribute("forward","请求转发");
return “forward:forward1.html”;
}
重定向:返回值前面加redirect
@RequestMapping(“/redirect1”)
public String redirect1(Model model){
model.addAttribute("forward","请求转发");
return “redirect:redirect1.html”;
}
7、springmvc怎么和ajax相互调用?
通过jackson框架可以把Java对象直接转换成js可以识别的json对象。加入jackson.jar。
8、解决post请求中文乱码
Web.xml中配置一个characterencodingFilter过滤器,设置成UTF-8
9、解决get请求中文乱码
1)、修改tomcat配置文件添加编码和工程编码一致
2)、对参数进行重新编码
String username = new String(request.getParameter(“userName”).getBytes(“IOS-8859-1”),“UTF-8”);
四、Spring Mvc 处理异常的三种方式
1、使用Spring Mvc提供的简单异常处理器SimpleMappingExceptionResolver
2、实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
3、使用@ExceptionHandler注解实现异常处理
1、使用Spring Mvc提供的简单异常处理器SimpleMappingExceptionResolver
1)、在Spring的配置文件applicationContext.xml中增加一下内容:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,不同异常的页名作为值 -->
<property name="exceptionMappings">
<props>
<prop key="cn.basttg.core.exception.BusinessException">error-business</prop>
<prop key="cn.basttg.core.exception.ParameterException">error-parameter</prop>
<!-- 这里还可以继续扩展对不同异常类型的处理 -->
</props>
</property>
</bean>
(使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好扩展性、对已有代码没有入侵性等优点,但该方法***仅能获取到异常信息,不能获取导致异常的对象***,对需要获取的除异常以外的数据的情况不适用。)
2、实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
1)、增加HandlerExceptionResolver接口的实现类MyExceptionHandler,代码如下:
public class MyExceptionHandler implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {
Map<String, Object> model = new HashMap<String, Object>();
model.put("ex", ex);
// 根据不同错误转向不同页面
if(ex instanceof BusinessException) {
return new ModelAndView("error-business", model);
}else if(ex instanceof ParameterException) {
return new ModelAndView("error-parameter", model);
} else {
return new ModelAndView("error", model);
}
}
}
2)、在Spring的配置文件applicationContext.xml中增加一下内容:
<bean id="exceptionHandler" class="cn.basttg.core.exception.MyExceptionHandler"/>
(使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好扩展性、对已有代码没有入侵性等优点,同时,在异常处理时***能获取导致出现异常的对象***,有利于提供更详细的异常处理信息。)
3、使用@ExceptionHandler注解实现异常处理
1)、增加BaseController类,在类中使用@ExceptionHandler注解声明异常处理,代码如下:
public class BaseController {
/** 基于@ExceptionHandler异常处理 */
@ExceptionHandler
public String exp(HttpServletRequest request, Exception ex) {
request.setAttribute("ex", ex);
// 根据不同错误转向不同页面
if(ex instanceof BusinessException) {
return "error-business";
}else if(ex instanceof ParameterException) {
return "error-parameter";
} else {
return "error";
}
}
}
2)、修改代码,使所有需要异常处理的Controller都继承该类
public class TestController extends BaseController
(具有集成简单、可扩展性好、不需要Spring配置等优点,但是该方式***对已有代码存在入侵性***,需要修改已有代码,使得相关类继承BaseController。 在异常处理时不能获取除异常以外的数据。)
4、未捕获异常的处理
对Unchecked Exception而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行响应的捕获和处理,则我们可能不得不面对尴尬的404、500……等服务器内部错误提示页面。
我们需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在Web.xml中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示页面。修改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>
五、Spring Mvc的控制器是不是单例模式?有什么问题?怎么解决?
单例模式(单例不用每次都 new,速度快性能好),多线程访问时会有线程安全的问题,会影响性能。解决方案是控制器(controller)里面不能写字段(成员变量)。
如果要硬设置成多例,controller上使用@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
六、SpringMvc常用的注解有哪些?
@RequestMapping:处理请求的 url映射的注解,可用于类或方法上
@RequestBody:实现接收http请求的json数据,将json转成java对象
@ResponseBody:实现将controller方法返回对象转换成json对象响应给客户
七、Spring Mvc的控制器的注解一般用哪个,有别的注解可以代替吗/
一般用@Controller,表示是表现层。不能用别的注解来代替。
八、如果在拦截请求中,我想拦截get方式提交的方法怎么配置?
可以在@RequestMapping注解里面加上method=RequestMethod.GET
九、怎么样在方法里面得到request或者session
直接在方法的形参中声明request,SpringMvc就自动把request对象传入
十、如果前台有很多个参数传入,并且这些参数都是一个对象的,那怎么样快速得到这个对象?
直接在方法中信声明这个对象,SpringMvc就自动会把属性值放在这个对象里面。
十一、Spring Mvc中函数的返回值是什么?
可以有很多类型,String,ModelAndView。ModelAndView类把视图和数据都合并到一起,但一般用String比较好。
十二、SpringMVC后台获取前台参数和向前台传值的几种方式** *******
https://my.oschina.net/u/2331760/blog/1811725
十三、怎么将modelmap里面的数据放入session里面?
在类上面加上@SessionAttribute注解,里面包含要放入session里面的key
十四、SpringMvc拦截器
1、什么是拦截器?
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作出响应的处理。例如通过拦截器可以进行了权限验证、记录请求信息的日志、判断用户是否登录等。
要使用SpringMVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1)、通过实现HandlerInteceptor接口,或继承HandlerInterceptor接口的实现类来定义。
2)、通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
以实现HandlerInterceptor接口方式为例,自定义拦截器类的代码如下:
public class CustomInterceptor implements HandlerInterceptor{
/*该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续往下执行;
当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
*/
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler)throws Exception {
return false;
}
/*该方法会在控制器方法调用之后,且视图解析器之前执行。可以通过此方法对请求域中的模型和视图做进一步的修改 */
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
}
/*该方法会在整个请求完成,即视图渲染结束之后执行。可以通过该方法实现一些资源清理、记录日志信息等工作。
*/
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
}
}
2、拦截器的配置
配置代码如下:
<!--配置拦截器-->
<mvc:interceptors>
<!--拦截器1-->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path=""/>
<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截-->
<!--下面这个bean配置的是这个拦截器类所拦截的内容-->
<bean class="com.ma.interceptor.CustomInterceptor"/>
</mvc:interceptor>
<!--拦截器2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.ma.interceptor.Interceptor2"/>
</mvc:interceptor>
注意:<mvc:interceptor >中的子元素必须按照上述代码中的配置顺序进行编写,即<mvc:mapping > <mvc:exclude-mapping > ,否则文件会报错。
3、整个拦截器的执行流程
preHandle方法:
该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续往下执行 ;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
postHandle方法:
该方法会在控制器方法调用之后,且视图解析器之前执行。可以通过此方法对请求域中的模型和视图做进一步的修改
afterCompletion方法:
该方法会在整个请求完成,即视图渲染结束之后执行。可以通过该方法实现一些资源清理、记录日志信息等工作。
【多个拦截器的执行流程】:当有多个拦截器同时工作时,它们的preHandle()方法会按照配置文件中拦截器的配置顺序执行,而它们的postHandle()方法和afterCompletion()方法则会按照配置顺序的反序执行。
十五、注解原理:
注解本质是一个继承了annotion的特殊接口,具体实现是java运行时生成的动态代理类,我们通过反射获取注解时,返回的是java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用annotionInvocationHandle的invoke方法,该方法会从membervalues这个map中检索出对应的值。而membervalues的来源是java常量池。
十六、SpringMVC文件上传
pom文件修改 添加commons-fileupload依赖
<dependency> <groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
servlet-context.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()){ StringfileName=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>
十七、SpringMVC实现RestFul服务
防止相关爬虫
提供一组设计原则和约束条件
于这种风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制
在Restful风格中,用户请求的url使用同一个url而用请求方式:get,post,delete,put…等方式对请求的处理方法进行区分,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口。
***Restful风格***的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这种风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
在Restful风格中,现有规定如下:
—GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的方式
—POST(CREATE):在服务器端创建一个资源,调用insert操作
—PUT(UPDATE):在服务器端更新资源,调用update操作
—PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(目前jdk1.7未实现,tomcat7不支持)
—DELETE(DELETE):从服务器端删除资源,调用delete语句。
1、SpringMVC中对restful的支持
案例:
如何在java构造没有扩展名的Restful url,如 /forms/1
SpringMvc Restful风格url配置实现
springmvc的resturl是通过@RequestMapping、***@PathVariable注解—>(访问路径变量)和@RequestBody---->(访问对象user、account之类)*** 提供的,通过如@RequestMapping(value="/blog/{id}",method=RequestMethod.DELETE),即可处理/blog/1的delete请求。
(前后台约定restful方式)
后台:
1)、GET请求配置
/**
*restful-->get 请求 执行查询操作 * @param id * @return */ @RequestMapping(value="queryAccountById02/{id}",method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_UTF8_VALUE) @ResponseBody
public MessageModel queryAccountById(@PathVariable Integer id){
MessageModel messageModel=new MessageModel();
if(null==id){
messageModel.sedCode(300);
messageModel.setMsg("参数非法!");
return messageModel;
}
messageModel.setResult(accountService.queryById(id));
return messageModel;
}
2)、POST请求配置
/*
* restful-->post 请求执行添加操作
* @param id
* @param aname
* @return
*/
@RequestMapping(value="saveAccount",method=RequestMethod.POST,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public MessageModel queryAccountById04(@RequestBody Account account){
MessageModel messageModel=new MessageModel();
try {
accountService.saveOrUpdateAccount(account);
} catch (ParamsException e) {
e.printStackTrace();
messageModel.setCode(e.getErrorCode());
messageModel.setMsg(e.getErrorMsg());
}catch (Exception e) {
e.printStackTrace();
messageModel.setCode(300);
messageModel.setMsg("操作失败!");
}
return messageModel;
}
3)PUT请求配置
/*
* restful-->put 请求执行更新操作
* @param id
* @param account
* @return
*/
@RequestMapping(value="update/{id}",method=RequestMethod.PUT,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public MessageModel queryAccountById04(@PathVariable Integer id,@RequestBody Account account){
MessageModel messageModel=new MessageModel();
try {
accountService.saveOrUpdateAccount(account);
} catch (ParamsException e) {
e.printStackTrace();
messageModel.setCode(e.getErrorCode());
messageModel.setMsg(e.getErrorMsg());
}catch (Exception e) {
e.printStackTrace();
messageModel.setCode(300);
messageModel.setMsg("操作失败!");
}
return messageModel;
}
4)、DELETE请求配置
/*
* restful-->delete 请求 执行删除操作
* @param id
* @return
*/
@RequestMapping(value="deleteAccountById/{id}",method=RequestMethod.DELETE,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public MessageModel queryAccountById05(@PathVariable Integer id){
MessageModel messageModel=new MessageModel();
try {
catch (ParamsException e) {
e.printStackTrace();
messageModel.setCode(e.getErrorCode());
messageModel.setMsg(e.getErrorMsg());
}catch (Exception e) {
e.printStackTrace();
messageModel.setCode(300);
messageModel.setMsg("操作失败!");
}
return messageModel;
}
前台:***
表单提交:
“GET/POST"在引入restful支持后,变成了"查询/插入“
在表单中埋一个“hidden”,它的“name”属性必须为“_method”,“value”属性为“PUT/DELETE”,这样SpringMVC会自动将该“hidden”控件的“value”解析为请求的方法。
ajax提交:type为:“GET/POST/PUT/DELETE"