请求映射
我们的 http 请求信息一般包含六部分信息:
1、请求方法,如GET或POST,表示提交的方式;
2、URL,请求的地址信息;
3、协议及版本;
4、请求头信息(包括Cookie信息);
5、回车换行(CRLF),头信息和请求体之间有空行;
6、请求内容区(即请求的内容或数据),如表单提交时的参数数据、URL请求参数(?abc=123 ?后边的)等。
我们可以看到有 1、2、4、6 一般是可变的,因此可以根据这四个可变的来映射到指定的方法
URL路径映射:使用URL映射请求到处理器的功能处理方法;
请求方法映射限定:如限定功能处理方法只处理GET请求;
请求参数映射限定:如限定只处理包含“abc”请求参数的请求;
请求头映射限定:如限定只处理“Accept=application/json”的请求
URL映射
@RequestMapping(value={“/test1”, “/user/create”}):多个 URL 路径可以映射到同一个处理器的功能处理方法。
@RequestMapping(value=”/users/**”):可以匹配“/users/abc/abc”
@RequestMapping(value=”/product?”):可匹配“/product1” 或“/producta”
@RequestMapping(value=”/product*”):可匹配“/productabc” 或“/product”
SpringMVC还提供了正则表达式风格,模板风格的URL映射,功能非常强大。
请求方法映射限定
@RequestMapping(value=”/hello”,method=RequestMethod.POST):指定此方法只能被 post 请求访问。
请求参数数据映射限定
@RequestMapping(params=”create”, method=RequestMethod.GET) :表示请求中有“create”的参数名且请求方法为“GET”即可匹配,如可匹配的请求 URL“http://×××/parameter1?create”;
@RequestMapping(params=”!create”, method=RequestMethod.GET):表示请求中没有“create”参数名且请求方法为“GET”即可匹配,如可匹配的请求 URL“http://×××/parameter1?abc”
@RequestMapping(params=”submitFlag=create”, method=RequestMethod.GET):表示请求中有“submitFlag=create”请求参数且请求方法为“GET”即可匹配,如请求 URL 为 http://×××/parameter2?submitFlag=create;
请求头数据映射限定
@RequestMapping(value=”/header/test1”, headers = “Accept”):表示请求的 URL 必须为“/header/test1”,且 请求头中必须有 Accept 参数才能匹配。
@RequestMapping(value=”/header/test3”,headers= “Content-Type=application/json”)表示请求的 URL 必须为“/header/test3”且请求头中必有“Content-Type=application/json”参数即可匹配。;
Controller 方法返回类型
ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
void
在 Controller 方法形参上可以定义 request 和 response,使用 request 或 response 指定响应结果:
1、使用 request 转发页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);
request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response);
2、可以通过response页面重定向:
response.sendRedirect("url")
response.sendRedirect("/springmvc-web2/itemEdit.action");
3、可以通过response指定响应结果,例如响应json数据如下:
response.getWriter().print("{\"abc\":123}");
String
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
至于数据,我们可以通过默认的Model或者ModelMap来传递参数。
通过 return "redirect:/xxx.jsp"/return "forward: /XXX.action" 来重定向或者转发
SpringMVC 中异常处理
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
在 SpringMVC 中,系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。springmvc 提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
1、编写自定义异常
为了区别不同的异常,通常根据异常类型进行区分,这里我们创建一个自定义系统异常。
如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。
package com.pngyul.springmvcmybatis.exception;
public class MyException {
// 异常信息
private String message;
public MyException() {
super();
}
public MyException(String message) {
super();
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2、自定义异常处理器
public class CustomHandleException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object obj,
Exception exception) {
// 定义异常信息
String msg;
// 判断异常类型
if (exception instanceof MyException) {
// 如果是自定义异常,读取异常信息
msg = exception.getMessage();
} else {
// 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
Writer out = new StringWriter();
PrintWriter s = new PrintWriter(out);
exception.printStackTrace(s);
msg = out.toString();
}
// 返回错误页面,给用户友好页面显示错误信息
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", msg);
modelAndView.setViewName("error");
return modelAndView;
}
}
3、在 springmvc.xml 中配置异常处理器
<!-- 配置全局异常处理器 -->
<bean class="com.pngyul.springmvcmybatis.exception.CustomHandleException"></bean>
4、测试
自行编写error页面、Controlller方法,在Controlller方法中抛出自定义异常即可
图片上传处理
在此之前得先配置一下虚拟目录
需求:更新图片到数据库并回显
1、导入jar包
2、在springmvc.xml中配置文件上传解析器
<!-- 配置文件上传实现类 -->
<bean name="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件上传大小 -->
<property name="maxUploadSize" value="5000000" />
</bean>
3、在商品修改页面,添加图片上传功能
<!-- 上传图片是需要指定属性 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>
4、在更新商品方法中添加图片上传逻辑
@RequestMapping("/updateItem.action")
//参数中MultipartFile pictureFile的pictureFile要与jsp表单对用name相一致
public String updateItemById(Items items,MultipartFile pictureFile) throws Exception{
//设置图片名称
String name = UUID.randomUUID().toString().replaceAll("-", "");
//获取图片扩展名
String ext = FilenameUtils.getExtension(pictureFile.getOriginalFilename());
//上传图片到指定路径
pictureFile.transferTo(new File("F:\\upload\\" + name + "." + ext));
// 设置图片名到商品中
items.setPic(name + "." + ext);
//更新商品
itemsService.updateItemById(items);
return "redirect:/itemEdit.action?id=" + items.getId();
}
Json数据交互
@RequestBody
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。
@ResponseBody
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
请求 json,响应 json 实现
<!-- 在editItem.jsp中加入如下代码 -->
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
$(function(){
//alert(1);
var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}';
// $.post(url,params,function(data){
//回调
// },"json");//
$.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);
}
});
});
</script>
<!--controller中方法-->
//json数据交互
@RequestMapping(value = "/json.action")
public @ResponseBody
Items json(@RequestBody Items items){
System.out.println(items);
return items;
}
这样内容为json数据的请求字符串就绑定在参数items对象中了
相反,返回值items是内容为json数据的字符串。
拦截器应用
登录检测
处理流程
1、有一个登录页面,需要写一个Controller访问登录页面
2、登录页面有一提交表单的动作。需要在Controller中处理。
a)判断用户名密码是否正确(在控制台打印)
b)如果正确,向session中写入用户信息(写入用户名username)
c)跳转到商品列表
3、拦截器。
a)拦截用户请求,判断用户是否登录(登录请求不能拦截)
b)如果用户已经登录。放行
如果用户未登录,跳转到登录页面。
代码实现
1、简单编写登录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>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/login.action">
<label>用户名:</label>
<br>
<input type="text" name="username">
<br>
<label>密码:</label>
<br>
<input type="password" name="password">
<br>
<input type="submit">
</form>
</body>
</html>
2、用户登陆Controller
@Controller
@RequestMapping("user")
public class UserController {
/**
* 跳转到登录页面
*
* @return
*/
@RequestMapping("toLogin")
public String toLogin() {
return "login";
}
/**
* 用户登录
*
* @param username
* @param password
* @param session
* @return
*/
@RequestMapping("login")
public String login(String username, String password, HttpSession session) {
// 校验用户登录
System.out.println(username);
System.out.println(password);
// 把用户名放到session中
session.setAttribute("username", username);
return "redirect:/item/itemList.action";
}
}
3、编写拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
// 从request中获取session
HttpSession session = request.getSession();
// 从session中获取username
Object username = session.getAttribute("username");
// 判断username是否为null
if (username != null) {
// 如果不为空则放行
return true;
} else {
// 如果为空则跳转到登录页面
response.sendRedirect(request.getContextPath() + "/user/toLogin.action");
}
return false;
}
4、在springmvc.xml配置拦截器
<mvc:interceptor>
<!-- 配置商品被拦截器拦截 -->
<mvc:mapping path="/item/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.itcast.ssm.interceptor.LoginHandlerInterceptor" />
</mvc:interceptor>
5、最后我们检测一下即可
有时候我们可能只需要实现三个回调方法中的某一个,如果实现 HandlerInterceptor 接口的话,三个方法必须实现不管你需不需要,此时 spring 提供了一个 HandlerInterceptorAdapter 适配器,允许我们只实现需要的回调方法。
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
//省略代码 此处所以三个回调方法都是空实现,preHandle返回true。
}
在我们编辑拦截器时继承该类即可