正文
Springmvc中的一些问题解决
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
Spring mvc中的异常
做统一处理,全局异常处理器
异常处理类代码: 必须实现接口 然后返回值是ModelAndView 那就可以做个展示页面了
package com.toov5.mvc.utils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;public class CustomerExceptionResolver implements HandlerExceptionResolver{ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) { ModelAndView mav = new ModelAndView();
mav.addObject("msg","系统发生异常,请联系管理员!");
mav.setViewName("msg"); return mav;
}}
这个类要告诉 spring mvc 所以要配置下:
<!-- 全局异常处理器配置 -->
<bean class="com.toov5.mvc.utils.CustomerExceptionResolver"> </bean>
访问controller 1/0的错误
所有页面都返回这个也不是很好~
升级:
更友好 更灵活的
自定义异常 :
自定义异常类:
package com.toov5.mvc.utils;public class MyException extends Exception { private String msg; public MyException(String msg) {
super();
this.msg = msg;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}}
Controller的使用:
@RequestMapping("queryVoid")
public void queryVoid(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException, MyException {
response.setCharacterEncoding("utf-8");
//假设这里是根据ID查询商品信息 搜索不到商品
if (true) {
throw new MyException("搜索失败!");
}
int i = 1/0;
PrintWriter writer = response.getWriter();
writer.println("rsponse打印的消息。。。。");
}
访问结果:
小结: 自定异常类 实现全局异常处理器 配置异常处理器
Spring mvc中的图片上传:
配置浏览器访问的 目录 在tomcat配置虚拟目录
本地的目录 映射到配置的虚拟目录
通过: http://localhost:8080/pic/aa.jpg 可以获取到图片
上传图片需要jar包
配置多媒体解析器: 配置的id也是固定不变的
<!-- 配置多媒体处理器 -->
<!-- 注意:这里id必须填写:multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 最大上传文件大小 -->
<property name="maxUploadSize" value="8388608" />
</bean>
Controller:
@RequestMapping("updateItem")
public String updatItem(Item item, Model model, MultipartFile pictureFile) throws IllegalStateException, IOException { //pictureFile图片名字要对应
//防止被覆盖 图片新名字
String newName = UUID.randomUUID().toString();
String oldName = pictureFile.getOriginalFilename(); //图片原来的名字。
//后缀获取
String sux = oldName.substring(oldName.lastIndexOf("."));
//新建本地文件流
File file = new java.io.File("C:\\Users\\Administrator\\Desktop\\pics\\"+newName+sux);
//写入本地磁盘
pictureFile.transferTo(file); //写入本地磁盘
//保存图片到数据库
item.setPic(newName+sux); model.addAttribute("item",item);
model.addAttribute("msg","修改商品信息成功!");
return "itemEdit"; }
前端:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改商品信息</title></head>
<body>
<span>${msg}</span>
<!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
<!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
<form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action" method="post" enctype="multipart/form-data">>
<input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }" /></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${item.price }" /></td>
</tr> <tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime"
value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
</tr>
<tr>
<td>商品图片</td>
<td>
<c:if test="${item.pic !=null}">
<img src="/pic/${item.pic}" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="pictureFile"/>
</td>
</tr> <tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
</td>
</tr>
</table> </form>
</body></html>
注意:
前端表格:<form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action" method="post" enctype="multipart/form-data"> >
上传图片时候 前端要注意传输类型 并且是post的 get没办法提交文件 在url拼接
关于JSON的交互
用JSON不用HTML 解析方便 不占用大量的网络传输量
开发:
jar包
在Controller里面加个
@Responbody
然后 可以返回 对象类型了
页面获取到的是Json字符串!
@RequestMapping("getItem")
@ResponseBody
public Item getItem() {
Item item =itemService.getItemById(3);
return item;
}
传入Json
为啥加了
@ResponseBody 可以实现json的响应支持?原因是:
<!-- 配置注解驱动,相当于同时使用最新处理器映射跟处理器适配器,对json数据响应提供支持 同时使用自定义转换器Myconvert-->
<mvc:annotation-driven conversion-service="MyConvert"/>
传入JSON:
@RequestMapping("getItem")
@ResponseBody
public Item getItem(@RequestBody Item item) {
System.out.println(item);
item.setName("张三");
return item;
}
出入的JSON 用Item类型的接受 字段是对应的 并且一定要加注解 @RequestBody
关于Restful 不是协议 也不是标准 是个风格!
//RESTful风格url上的参数通过{}点位符绑定
//点位符参数名与方法参数名不一致时,通过@PathVariable绑定
@RequestMapping("item/{id}") //url最后的参数值 被下面的括号中的id获取到
public String itemQuery(@PathVariable Integer id, Model model) {
Item item =itemService.getItemById(id);
model.addAttribute("item",item);
return "itemEdit"; }
用个大括号做个占位符
如果名字不一致 需要稍加改动
@RequestMapping("item/{id}") //url最后的参数值 被下面的括号中的id获取到
public String itemQuery(@PathVariable(@PathVariable("id")) Integer idUse, Model model) {
注意区别: @RequestParam 的参数是通过 url?拼接来的
@PathVariable 是url后面占位符的 参数
访问:
http://localhost:8080/SSM01/item/3.action
这里需要加 .action的后缀
修改下Spring mvc 配置文件可以搞定
关于Spring mvc拦截器:
/** : 拦截所有请求 包括二级以上目录
拦截器:
package com.toov5.mvc.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class MyInterceptor implements HandlerInterceptor { public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception { System.out.println("...afterCompletion...");
} public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception { System.out.println(".......postHandle......");
} public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("........preHandle......");
return true; //对拦截请求放行 true放行
}}
进行配置 告诉Spring mvc
<!-- 全局异常处理器配置 -->
<bean class="com.toov5.mvc.utils.CustomerExceptionResolver"> </bean> <mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.toov5.mvc.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
Controller做标记(观察执行顺序):
@RequestMapping( value="itemList", method={RequestMethod.POST,RequestMethod.GET})
public ModelAndView itemList() {
ModelAndView mav = new ModelAndView();
List<Item> itemList = itemService.getItemList();
mav.addObject("itemList",itemList);
mav.setViewName("itemList"); //jsp的名字
System.out.println("ItemController.itemList************执行了****************");
return mav;
}
访问后的执行结果:
注意这里修改了 日志的打印级别 否则打印的消息太细致 不容易观察:
详细介绍:
如果多个拦截器在一起呢?
再加一个拦截器 然后进行配置:
package com.toov5.mvc.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class MyInterceptor2 implements HandlerInterceptor { //方法执行后被执行 可以处理异常 或者清理资源 或者记录日志等操作
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception { System.out.println("...afterCompletion..2...");
}
//方法执行之后 同时可以获取到 ModelAndView 也就是返回视图之前 被执行
//设置页面的公用参数等操作
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception { System.out.println(".......postHandle..2......");
} //进入方法前被执行 登录拦截 权限校验 然后决定是否放行
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("........preHandle..2......");
return true; //对拦截请求放行 true放行
}}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.toov5.mvc.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.toov5.mvc.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
结果:
执行顺序 与 配置中的 顺序有关
一排人 钻山洞 钻进去 没出路 返回的过程了类似
如果第一个拦截器不放行: 只有这个方法执行了 目的地 网页也没有获取到
第一个放行 第二个不放行: 木有获取网页内容 拦截器只要放行 就会执行自己的 afterCompletion 不放行的是不被执行的 两个都执行才执行handler里面的方法
案例: 登录拦截器
如果没有登录 访问别的页面时候 会别拦截 跳转到 登录页面
如果登录了 当前回话里面 随便点击 随便跳转玩儿
拦截器负责拦截 这个请求 看看 session回话里面 有没有 登录信息标记 如果被标记了 就放行 如果没有那就拦截 跳转到登录页面
Jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/login.action">
用户名:<input type="text" name="username" /><br>
密码:<input type="password" name="password" /><br>
<input type="submit">
</form>
</body>
</html>
Controller:
package com.toov5.mvc.controller;import javax.servlet.http.HttpSession;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("user")
public class UserController { @RequestMapping("toLogin")
public String toLogin() {
return"login";
} @RequestMapping("login")
public String login(String username, String password,HttpSession session) {
if (username.equals("admin")) {
session.setAttribute("username", username);
return "redirect:/itemList.action"; //user 下面没有这个请求地址 这个是根目录下面的所以 /需要加上
}
return "login";
}}
拦截器:
package com.toov5.mvc.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class LoginInterceptor implements HandlerInterceptor { //方法执行后被执行 可以处理异常 或者清理资源 或者记录日志等操作
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception { System.out.println("...afterCompletion..2...");
}
//方法执行之后 同时可以获取到 ModelAndView 也就是返回视图之前 被执行
//设置页面的公用参数等操作
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception { System.out.println(".......postHandle..2......");
} //进入方法前被执行 登录拦截 权限校验 然后决定是否放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { Object object = request.getSession().getAttribute("username");
if (object == null) {
//这里要写全路径
response.sendRedirect(request.getContextPath()+"/user/toLogin.action");
}
return true; //对拦截请求放行 true放行
}}
mvc配置:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.toov5.mvc.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.toov5.mvc.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- 配置不拦截目录 -->
<mvc:exclude-mapping path="/user/**"/> <!-- user打头的都不拦截 -->
<bean class="com.toov5.mvc.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
后期补充了:
package com.toov5.controller;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
public class HelloController {
@RequestMapping("hello")
public ModelAndView hello(HttpServletRequest request){ ////////////可以很灵活的使用 HttpServletRequest
System.out.println("hello springmvc...");
ModelAndView mav = new ModelAndView();
//设置模型数据,用于传递到jsp
//mav.addObject("msg", "hello springmvc......");
//设置视图名字,用于响应用户
request.setAttribute("msg", "httpservletrequest的内容");
mav.setViewName("/WEB-INF/jsp/hello.jsp"); return mav;
}
}