SpringMVC 核心技术(二)

请求映射

我们的 http 请求信息一般包含六部分信息:

1、请求方法,如GET或POST,表示提交的方式;
2URL,请求的地址信息;
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。  
} 

在我们编辑拦截器时继承该类即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值