spring MVC部分
一、处理请求的流程
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping,DispatcherServlet 接收到请求后, 将根据请求信息(包括 URL、 HTTP 方法、请求头、请求参数、 Cookie 等)及 HandlerMapping 的配置找到处理请求的处理器(Handler).可将 HandlerMapping 看成路由控制器,将 Handler 看成目标主机;
3、 DispatcherServlet——>HandlerAdapter,通过 HandlerAdapter 对 Handler 进行封装,再以统一的适配器接口调用 Handler从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
二、相关注解说明
@Controller:声明控制器
@Service: 声明Service组
@Repository: 声明Dao组件
@Component:泛指组件(不推荐)
@RequestMapping:将URL映射到整个类或特定的方法上
consumes-指定处理请求的提交内容类型Content-Type,例如 application/json,text/html。
produces-指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
value-指定请求的实际地址,指定的地址可以是URI Template 模式。
params-指定request中必须包含某些参数值是,才让该方法处理。
headers-指定request中必须包含某些指定的header值,才能让该方法处理请求。
method-指定请求方式,枚举类RequestMethod。
@Transactional:事务管理(参考:http://www.cnblogs.com/caoyc/p/5632963.html)
事物传播行为介绍:
@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
事务隔离级别:
@Transactional(isolation = Isolation.DEFAULT):使用数据库默认的隔离级别(默认情况下)
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
大多数数据库的默认隔离级别为: Read Commited,如Sql Server , Oracle.
少数数据库默认的隔离级别为Repeatable Read, 如MySQL InnoDB存储引擎
- 读未提交:read uncommitted :事物A和事物B,事物A未提交的数据,事物B可以读取到
- 读已提交:read committed:事物A和事物B,事物A提交的数据,事物B才能读取到
- 可重复读:repeatable read:事务A和事务B,事务A提交之后的数据,事务B读取不到,事务B是可重复读取数据
- 串行化:serializable:事务A和事务B,事务A在操作数据库时,事务B只能排队等待
脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据
@Resource: 用于注入,( j2ee提供的 ) 默认按名称装配,找不到再按照类型
@Autowired: 用于注入, 默认按类型装配
@PathVariable:注解方法参数并将其绑定到URI模板变量的值。例如:
@ResponseBody
@RequestMapping(value="load_{name}",produces="application/json;charset=UTF-8")
public String loadAddress(@PathVariable("name") String name, HttpServletRequest request,HttpServletResponse response) {
String id = request.getParameter("id");
UsrAddress add = addressService.loadPrimaryAddress(Long.valueOf(id), 1L);
System.out.println(name);
return JSON.toJSONString(add);
}
@RequestParam:将请求的参数绑定到方法中的参数上。其实即使不配置该参数,注解也会默认使用该参数
@RequestBody:用于content type为json格式请求,可以将请求的json内容,转为javabean。例如:
@ResponseBody
@RequestMapping(value="test",produces="application/json;charset=UTF-8")
public String test(@RequestBody UsrAddress add,HttpServletRequest request,HttpServletResponse response) {
System.out.println(add.getProvince());
return JSON.toJSONString(add);
}
@ResponseBody:返回的数据不是页面,而是其他文本格式的数据时(如json、xml等)。注意与RequestBody的区别,RequestBody是用于请求数据是json/xml。
@RequestHeader:可以把Request请求header部分的值绑定到方法的参数上。例如:
@ResponseBody
@RequestMapping(value="test",produces="application/json;charset=UTF-8")
public String test(@RequestHeader("Accept-Encoding") String encoding,HttpServletRequest request,HttpServletResponse response) {
System.out.println(encoding);
return "";
}
@CookieValue:可以把请求中关于cookie的值绑定到方法的参数上
@SessionAttributes:把数据存储到session中。例如:
@Controller
@RequestMapping(value = "/address")
@SessionAttributes("address")
public class AddressController {
@Resource
private IAddressService addressService;
@RequestMapping(value="test")
public String test(ModelMap map) {
UsrAddress address=new UsrAddress();
address.setProvince("02");
map.put("address", address);
return "success";
}
}
@ModelAttribute:可以作用在方法或方法参数上,当它作用在方法上时,该Controller的所有方法在调用前,先执行此@ModelAttribute注解的方法;当作用在方法参数上时,会把请求的参数,赋值到javabean对象,另外还可以从session中取值。例如:
@ResponseBody
@RequestMapping(value="test1",produces="application/json;charset=UTF-8")
public String test1(@ModelAttribute("address") UsrAddress address,HttpServletRequest request,HttpServletResponse response) {
System.out.println(address.getProvince());
return JSON.toJSONString(address);
}
三、拦截器
1、继承HandlerInterceptorAdapter,重写需要的方法:
preHandle:该方法将在Controller处理之前进行调用
postHandle:在Controller的方法调用之后,DispatcherServlet进行视图的渲染之前执行,可以修改ModelAndView(preHandle方法的返回值为true时才会执行)
afterCompletion:方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行,主要作用是用于清理资源(preHandle方法的返回值为true时才会执行)
afterConcurrentHandlingStarted():这个方法会在Controller方法异步执行时开始执行, 而Interceptor的postHandle方法则是需要等到Controller的异步执行完才能执行。
注:有多个拦截器满足时,先要执行全部拦截器的preHandle,再执行全部拦截器的postHandle,最后执行全部的afterCompletion。执行单个preHandle顺序是按照配置拦截器的先后,执行postHandle和afterCompletion顺序跟配置相反。
2.配置spring-mvc.xml
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<bean class="com.lzj.test.interceptor.AllInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/address/test1.do"/>
<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
<bean class="com.lzj.test.interceptor.Interceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
3.过滤器和拦截器的区别
拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
拦截器不依赖与servlet容器,归spring管理可以使用spring的资源;过滤器依赖与servlet容器
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
拦截器更灵活可以多次被调用,而过滤器只能在容器初始化时被调用一次
四、容器启动初始化
1.实现spring接口 ApplicationListener<ContextRefreshedEvent>,重写onApplicationEvent方法,实现自己的初始化逻辑
2.spring 配置文件定义bean
<bean class="com.lzj.test.listener.InitListener"/>
五、文件上传
1.spring配置文件定义CommonsMultipartResolver
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
2.Controller代码
@RequestMapping("springUpload")
public String springUpload(HttpServletRequest request) {
try {
long startTime = System.currentTimeMillis();
// 将当前上下文初始化给 CommonsMutipartResolver (多部分解析器)
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
// 检查form中是否有enctype="multipart/form-data"
if (multipartResolver.isMultipart(request)) {
// 将request变成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
// 获取multiRequest 中所有的文件名
Iterator iter = multiRequest.getFileNames();
while (iter.hasNext()) {
// 一次遍历所有文件
MultipartFile file = multiRequest.getFile(iter.next().toString());
if (file != null) {
String path = "D:/" + file.getOriginalFilename();
// 上传
file.transferTo(new File(path));
}
}
}
long endTime = System.currentTimeMillis();
System.out.println("运行时间:" + String.valueOf(endTime - startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}
3.jsp页面
<form name="Form" action="springUpload.do" method="post" enctype="multipart/form-data">
<h1>使用spring mvc提供的类的方法上传文件</h1>
<input type="file" name="file">
<input type="submit" value="upload"/>
</form>
六、其他
1.Controller跳转其他Controller
return的String为“redirect:/xx/xx.do”