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;
    }
}

 

posted @ 2019-01-14 03:07  toov5  阅读(270)  评论(0编辑  收藏  举报