目录
基础
开发架构一般基于两种形式,一种是C/S架构(客户端/服务器),另一种是B/S架构(浏览器/服务器),javaEE开发中,几乎都是基于B/S架构的开发.B/S架构中三层架构:表现层(web层)、业务层(service层)、持久层(dao层)。
MVC设计模式,是模型(model)、视图(view)、控制器(controller),用于设计创建web应用程序表现层的模式。每一层只编写自己的东西,不编写任何其他的代码,分层是为了解耦,解耦是为了维护方便和分工协作。
SpringMVC全名Spring WebMVC基于Java实现MVC设计模型的请求驱动类型的轻量级web框架,属于SpringFrameWork的后续产品。
SpringMVC通过一套注解,让一个简单的Java类成为处理请求的控制器,无须实现任何接口,支持RESTful风格的请求。 本质是对servlet的封装,简化了servlet的开发,作用:接收请求、返回响应、跳转页面。
请求处理流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 处理器映射器根据请求url找到具体的Handler(后端控制器),生成处理器对象及处理器拦截器(有则生成)一并返回DispatcherServlet
- DispatcherServlet调用HandlerAdapter处理器适配器去调用Handler
- 处理器适配器执行Handler
- Handler执行完成给处理器适配器返回ModelAndView
- 处理器适配器向前端控制器返回ModelAndView(框架中一个底层对象包括Model和view)
- 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名来解析真正的视图
- 视图解析器向前端控制器返回View
- 前端控制器进行视图渲染,将模型数据填充到request域
- 前端控制器向用户响应结果
组件
HandlerMaping(处理器映射器)
HandlerAdapter(处理器适配器)
HandlerExceptionResolver(处理handler产生的异常情况)
ViewResolver(视图解析器)
RequestToViewNameTranslator(从请求中获取ViewName)
LocaleResolver(从请求中解析出Locale)
ThemeResolver (用于解析主题)
MultipartResolver(用于上传请求)
FlashMapManager(用于重定向时的参数传递)
接收请求参数
了解下参数绑定:取出参数值绑定到handler方法的形参上。
- 默认支持ServletAPI作为方法参数
@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
String id = request.getParameter("id");
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
2.绑定简单类型参数
简单数据类型:8种基本数据类型及其包装类型(推荐使用,可以为null)
对于boolean类型的参数,值为true或false,0或1
/*
* SpringMVC 接收简单数据类型参数 url:/demo/handle03?id=1
*
* 注意:接收简单数据类型参数,直接在handler方法的形参中声明即可,框架会取出参数值然后绑定到对应参数上
* 要求:传递的参数名和声明的形参名称保持一致
*/
@RequestMapping("/handle03")
public ModelAndView handle03(@RequestParam("ids") Integer id, Boolean flag) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
3.绑定pojo类型参数
/*
* SpringMVC接收pojo类型参数 url:/demo/handle04?id=1&username=zhangsan
*
* 接收pojo类型参数,直接形参声明即可,类型就是Pojo的类型,形参名无所谓
* 但是要求传递的参数名必须和Pojo的属性名保持一致
*/
@RequestMapping("/handle04")
public ModelAndView handle04(User user) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
4.绑定pojo包装对象参数
/*
* SpringMVC接收pojo包装类型参数 url:/demo/handle05?user.id=1&user.username=zhangsan
* 不管包装Pojo与否,它首先是一个pojo,那么就可以按照上述pojo的要求来
* 1、绑定时候直接形参声明即可
* 2、传参参数名和pojo属性保持一致,如果不能够定位数据项,那么通过属性名 + "." 的方式进一步锁定数据
*
*/
@RequestMapping("/handle05")
public ModelAndView handle05(QueryVo queryVo) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
5.绑定日期类型参数
/**
* 绑定日期类型参数
* 定义一个SpringMVC的类型转换器 接口,扩展实现接口接口,注册实现
* @param birthday
* @return
*/
@RequestMapping("/handle06")
public ModelAndView handle06(Date birthday) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
自定义转换器要实现Converter<S,T>,S为源类型T为目标类型,实现convert方法,完成日期的转换。
要注册自定义类型转换器
<mvc:annotation-driven conversion-service="conversionServiceBean"/>
<!--注册自定义类型转换器-->
<bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.lagou.converter.DateConverter"></bean>
</set>
</property>
</bean>
Restful风格的请求支持
restful是一种web软件架构风格,不是标准也不是协议,倡导的是一个资源定位及资源操作的风格。
优点:结构清晰、符合标准、易于理解、扩展方便
特性:资源(如文本、图片等用URI-资源定位符指向它,想要获取资源,直接访问URI)、表现层(资源呈现出来的形式,如HTML、JSON等)、状态转化(发出请求,代表了客户端和服务器的一次交互过程)
HTTP协议是无状态的协议,所有状态在服务器端,客户端想要操作服务器通过某种手段,操作方式动词:GET POST PUT DELETE
举例:
/account/1 HTTP GET得到id = 1 的account /account/1 HTTP DELETE删除 id = 1的account
/account/1 HTTP PU更新 id = 1 的account
URL:资源定位符,通过URL地址去定位互联网中的资源。
SpringMVC中支持这种风格,使用@PathVariable注解获取请求URL中的路径变量。
/*
* restful get /demo/handle/15
*/
@RequestMapping(value = "/handle/{id}",method = {RequestMethod.GET})
public ModelAndView handleGet(@PathVariable("id") Integer id) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
注意:
对于put和delete请求使用post传递到服务器,后端具体接收method中还是相应的put或post,这时要在web.xml中配置请求方式过滤器
将特定的post转换为put和delete
hiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
AjaxJson交互
前端到后台,使用注解@RequestBody
后台到前台,使用数据@ResponseBody
高级技术
监听器、过滤器和拦截器
监听器:随web应用的启动而启动,只初始化一次,然后会一直运行监视,随web应用的停止而销毁
过滤器:对request请求起到过滤的作用
拦截器:是springMVC表现层框架本身的,不会拦截jsp/html/css的访问等,只会拦截访问的控制器方法即handler,会在handler业务逻辑执行之前拦截一次,逻辑执行完毕但未跳转页面之前拦截一次,在跳转页面之后拦截一次。
处理multipart形式的数据
<!--文件上传所需坐标-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--多元素解析器
id固定为multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件大小上限,单位是字节,-1代表没有限制也是默认的-->
<property name="maxUploadSize" value="5000000"/>
</bean>
@RequestMapping(value = "/upload")
public ModelAndView upload(MultipartFile uploadFile, HttpSession session) throws IOException {
// 处理上传文件
// 重命名,原名123.jpg ,获取后缀
String originalFilename = uploadFile.getOriginalFilename();// 原始名称
// 扩展名 jpg
String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
String newName = UUID.randomUUID().toString() + "." + ext;
// 存储,要存储到指定的文件夹,/uploads/yyyy-MM-dd,考虑文件过多的情况按照日期,生成一个子文件夹
String realPath = session.getServletContext().getRealPath("/uploads");
String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File folder = new File(realPath + "/" + datePath);
if(!folder.exists()) {
folder.mkdirs();
}
// 存储文件到目录
uploadFile.transferTo(new File(folder,newName));
// TODO 文件磁盘路径要更新到数据库字段
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date",date);
modelAndView.setViewName("success");
return modelAndView;
}
控制器中的异常处理
// 可以让我们优雅的捕获所有Controller对象handler方法抛出的异常
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handleException(ArithmeticException exception, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg",exception.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
基于Flash属性的跨重定向请求数据传递
/**
* SpringMVC 重定向时参数传递的问题
* 转发:A 找 B 借钱400,B没有钱但是悄悄的找到C借了400块钱给A
* url不会变,参数也不会丢失,一个请求
* 重定向:A 找 B 借钱400,B 说我没有钱,你找别人借去,那么A 又带着400块的借钱需求找到C
* url会变,参数会丢失需要重新携带参数,两个请求
*/
@RequestMapping("/handleRedirect")
public String handleRedirect(String name, RedirectAttributes redirectAttributes) {
//return "redirect:handle01?name=" + name; // 拼接参数安全性、参数长度都有局限
// addFlashAttribute方法设置了一个flash类型属性,该属性会被暂存到session中,在跳转到页面之后该属性销毁
redirectAttributes.addFlashAttribute("name",name);
return "redirect:handle01";
}