版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33322074/article/details/89666776
文章目录
1. springMVC学习笔记二:参数绑定、文件上传、拦截器学习
2. springMVC高级参数绑定
2.1. springMVC绑定数组
- 主要修改Controller层的接收参数类型,例如修改接收参数类型为Integer[] .
- 修个jsp页面。
<c:forEach items="${itemList }" var="item">
<tr>
<td><input type="checkbox" name="ids" value="${item.id }"></td>
- 接收参数为Integer[] ids。注意ids一定要和前台的参数一样,springMVC接收参数的机制就是要两者相同。
@RequestMapping(value="/deletes.action")
public ModelAndView deleteitem(Integer[] ids) {
- 还有一种方法,再对象包装类中创建一个Integer[] 属性。让后再让Controller层方法的形参为该包装类。
public ModelAndView deletes(QueryVo vo){
- 包装类,必须保证Integer[] 对象和jsp中的id一样。即:ids和jsp中的id值相同。
public class QueryVo {
//商品
private Items items;
Integer[] ids;
2.2. springMVC绑定LIst集合
- 必须使用包装类,在包装类中创建list集合
public class QueryVo {
private List<Items> itemsList;
- 在jsp页面通过JSTL表达式进行赋值
- springMVC技术只要让对象名字和包装类中的属性名字相同,就能实现包装类从jsp页面中获取对应的值。
<c:forEach items="${itemList }" var="item" varStatus="s">
<tr>
<td><input type="checkbox" name="ids" value="${item.id }"></td>
<td><input type="text" name="itemsList[${s.index}].name" value="${item.name }"></td>
<td><input type="text" name="itemsList[${s.index }].price" value="${item.price }"></td>
- 在Controller层给方法添加包装类形参。
public ModelAndView updates(QueryVo vo){
2.3. RequestMapping映射路径标签
- URl路径映射
- 可以添加多路径,这样在请求时可以多路径请求不会报错。
- 用逗号隔开。
@RequestMapping(value = {"/item/itemlist.action","/item/itemlisthaha.action"})
- 添加在类上面
- 添加在类的上面相当于全局,在该目录下。也就是说如果添加到类的上面,该类里的所有请求都要从该路径下进行。
- 请求方法限定
- 限定提交方式是get还是post提交,如果限定了提交类型,却用其他的方式提交就会报错。
- 报错内容:HTTP Status 405 - Request method ‘GET’ not supported
@RequestMapping(value = "itemList",method = RequestMethod.POST)
//两种方法到可以
@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
2.4. Controller层方法返回值
2.4.1. ModelAndView作为返回值
- ModeAndView
- 是无敌的,带着数据,返回视图路径。
2.4.2. String作为返回值
- String作为返回值
- 包含视图路径,为了能够带着数据,提供一个形参Model,让它带着数据。这个官方推荐,
- 实现类数据和视图分离,符合高内聚,低耦合思想。
- 用model.addAttribute()方法给域对象赋值。
@RequestMapping(value = {"/item/itemlist.action","/item/itemlisthaha.action"})
public String itemList(Model model,HttpServletRequest request,HttpServletResponse response) throws MessageException{
List<Items> list = itemService.selectItemsList();
model.addAttribute("itemList", list);
return "itemList";
- String作为返回值实现重定向和转发
- 实现重定向
return "redirect:/itemEdit.action?itemId=" + item.getId();
- String作为返回值实现转发
return "forward:/itemEdit.action";
2.4.3. Void作为返回值
- 主要用于ajax异步请求,ajax返回类型是json格式,不是直接的数据,因此String作为返回值也不能接收ajax数据。
- 在Controller方法形参上可以定义request和response,使用request或response指定响应结果:
- 使用request转发页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);
request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response);
- 可以通过response页面重定向:
response.sendRedirect("url")
response.sendRedirect("/springmvc-web2/itemEdit.action");
- 可以通过response指定响应结果,例如响应json数据如下:
response.getWriter().print("{\"abc\":123}");
3. springMVC异常处理器
3.1. 异常处理器思路
- springMVC提供的异常处理器不是用来处理异常的,是用来捕获异常的,异常捕获后由程序员开发的自定义异常处理器处理异常。
- 异常处理器图解
- springMVC提供的是一个异常接口HandlerExceptionResolver,我们需要写一个类实现该接口。
3.2. 异常分类
3.2.1. 预知异常
- 预期异常就是预先开发人员可以知道的异常,对其进行处理。
- 从上图可以看出,如果程序出现异常,就会向上抛出,直到抛给异常处理器的接口,然后有异常处理器实现类完成异常的处理。
- 首先发现预知异常,向上抛出
- 异常被抛给MessageException,这是一个异常信息实体类,用于存储异常信息。
@RequestMapping(value = {"/item/itemlist.action","/item/itemlisthaha.action"})
public String itemList(Model model,HttpServletRequest request,HttpServletResponse response) throws MessageException{
// Integer i = 1/0;
//从Mysql中查询
List<Items> list = itemService.selectItemsList();
if(null == null){
throw new MessageException("商品信息不能为空");
}
model.addAttribute("itemList", list);
return "itemList";
}
- 异常实体类
- 异常实体类要继承Exception。
- 将预知异常抛出到异常实体类,异常实体类接收。
public class MessageException extends Exception{
private String msg;
public MessageException(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- 异常实体类接收后,会被注入在springMVC.xml的异常实现类取出。
<!-- Springmvc的异常处理器 -->
<bean class="com.it.springmvc.exception.CustomExceptionResolver"/>
- 异常处理器实现类获取异常信息,并进行处理
- 实现接口,并从异常实体类中获取异常信息。
- 异常被抛出后,DipatcherServlet前度控制器会自动寻找异常处理器接口,异常处理器接口再从springMVC.xml中寻找其实现类,执行该实现类。
- 该实现类实现接口方法,并获取报错信息,或者重定向到错误页面显示。
public class CustomExceptionResolver implements HandlerExceptionResolver{
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object obj,
Exception e) {
ModelAndView mav = new ModelAndView();
//判断异常为类型
if(e instanceof MessageException){
//预期异常
MessageException me = (MessageException)e;
mav.addObject("error", me.getMsg());
}else{
mav.addObject("error", "未知异常");
}
mav.setViewName("error");
return mav;
}
3.2.2. 运行时异常
- 运行时的异常,主要通过规范代码开发,测试通过手段减少运行时异常发生。
4. springMVC上传图片
4.1. 步骤分析
- 给上传文件的方法添加上传文件类参数:即文件接口MultipartFile
- 在springMVC.xml中添加bean注入文件上传实现类用于实现1步的接口。
- 配置虚拟目录,创建文件保存本地的路径
- 添加上传文件的jar:commons-fileupload-1.2.2.jar,commons-io-2.4.jar
- 为了防止上传的文件重名,生成uuid并去掉四个-为文件名
- 获取扩展名将文件上传到本地
- 将文件存储到数据库中
- 重定向验证该id下的图像
4.2. 实现代码
- 给文件接口添加MultiPartFile形参
public String updateitem(QueryVo vo,MultipartFile pictureFile)
- 配置springMVC.xml
- 用于配置上传文件的实现类
<!-- 上传图片配置实现类 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上传图片的大小 B 5M 1*1024*1024*5-->
<property name="maxUploadSize" value="5000000"/>
</bean>
- 配置服务器虚拟目录,将文件保存到本地文件夹
- 设置uuid
- 用空字符替换掉java生成的uuid中的“-”
String name = UUID.randomUUID().toString().replaceAll("-", "");
- 获取图像的后缀名
String ext = FilenameUtils.getExtension(pictureFile.getOriginalFilename());
- 将文件上传到虚拟目录
pictureFile.transferTo(new File("D:\\upload\\" + name + "." + ext));
- 将文件名存储到数据库
vo.getItems().setPic(name + "." + ext);
itemService.updateItemsById(vo.getItems());
- jsp页面获取数据库中的图片,会从虚拟目录中获取。
<c:if test="${item.pic !=null}">
<img src="/pic/${item.pic}" width=100 height=100/>
<br/>
</c:if>
5. springMVC实现json格式的数据交互
5.1. springMVC封装json数据为java对象,并将数据封装为json数据
- spingMVC使用@RequestBody注解用于读取http请求的字符串,通过springMVC提供的HttpMessageConverter接口将读取到的内容(json数据)转换为java对象并绑定到Controller方法的参数。
- springMVC使用@ResponseBody注解将Controller的方法返回的对象,通过springMVC提供的HttpMessageConverter接口转换为指定的格式的数据如:json,xml等通过Resonse响应给客户端。
@RequestMapping(value = "/json.action")
public @ResponseBody
Items json(@RequestBody Items items){
// System.out.println(items);
return items;
}
5.2. 前台ajax代码
- 为什么使用Ajax代码呢
- ajax最大的优点就是能在不刷新整个页面的情况下维持与服务器通信
- 异步与服务器通信,使用异步的方式与服务器登录,不打断用户的操作。
- 前端和后端负载均衡:将一些后端的工作移动到前端,减少服务器与带宽的负担。
- 基于规范被广泛支持:不需要下载浏览器插件或者小程序,但需要客户允许javaScript在浏览器上执行。
- 界面与应用分离:Ajax使得界面与应用分离,也就是数据与呈现分离。
$(function(){
var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}';
$.ajax({
url : "${pageContext.request.contextPath }/json.action",
data : params,
contentType : "application/json;charset=UTF-8",//发送数据的格式
type : "post",
dataType : "json",//回调
success : function(data){
alert(data.name);
}
});
});
6. RESTful编程风格
- 以京东为例
- 互联网上的所有事物都可以被抽象认为资源,如京东的资源编号。
- 在电子商务网站中你不可能给每件商品想一个名字,只能用编号来代替。
- 传统方式和RESTful风格区别
- 用数字代替了名字,直接写id名,不要写其他的了。
- RESTful风格做法
- 只需要修个两点即可,在请求路径上获取id值,在方法形参中添加路径变量的注解。
- 也就是从url请求路径上获取参数。
//RestFul风格的开发
@RequestMapping(value = "/itemEdit/{id}.action")
public ModelAndView toEdit1(@PathVariable Integer id,
HttpServletRequest request,HttpServletResponse response
,HttpSession session,Model model){
- 原来代码
@RequestMapping(value = "/itemEdit.action")
public ModelAndView toEdit(Integer id,
7. springMVC的拦截器学习
7.1. 拦截器用途
- 当用户执行一个方法时需要知道该用户是否已经登录。如果登录了就执行,没有登录就重定向到登录页面。
7.2. 拦截器的使用
- 在springMVC.xml中配置拦截器
- 可以在拦截器栈中配置多个拦截器
- 可以用"/**"/表示有多个请求目录:例如:item/itemlist/abc/a.action,也表示拦截所有请求。
<!-- SPringmvc的拦截器 -->
<mvc:interceptors>
<!-- 多个拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- 自定义的拦截器类 -->
<bean class="com.it.springmvc.interceptor.Interceptor1"/>
</mvc:interceptor>
<!-- <mvc:interceptor>
<mvc:mapping path="/**"/>
自定义的拦截器类
<bean class="com.it.springmvc.interceptor.Interceptor2"/>
</mvc:interceptor> -->
</mvc:interceptors>
- 需要自定义拦截器类
- 该自定义类需要实现HandlerInterceptor接口,实现拦截器处理器接口。
- 包含三个方法preHandle方法执行前,postHandle方法执行后,afterCompletion页面渲染后。
- 如果有多个拦截器三个方法的执行顺序遵循5个规则
- preHandle按拦截器定义顺序调用。
- postHandle按拦截器定义逆序调用
- afterCompletion按拦截器定义逆序调用
- postHandle在拦截器栈内所有拦截器返回成功才调用。一个拦截器失败,就不会调用了。
- afterCompletion在preHandle返回true才调用。
- 自定义拦截器类实现判断是否登录案例
- 第一是先获取用户提交的URI是否为login.action因为这个不需要再拦截了。
- 再判断该session域是否有值,没有表示没有登录,重定向到登录界面。否则通过拦截器,放行。
public class Interceptor1 implements HandlerInterceptor{
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
System.out.println("方法前 1");
//判断用户是否登陆 如果没有登陆 重定向到登陆页面 不放行 如果登陆了 就放行了
// URL http://localhost:8080/springmvc-mybatis/login.action
//URI /login.action
String requestURI = request.getRequestURI();
if(!requestURI.contains("/login")){
String username = (String) request.getSession().getAttribute("USER_SESSION");
if(null == username){
response.sendRedirect(request.getContextPath() + "/login.action");
return false;
}
}
return true;
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("方法后 1");
}
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("页面渲染后 1");
}