SpringMVC_02

1 响应数据和结果视图

1.1 返回值分类

01 字符串

//从超链接跳转
 <a href="user/testString">testString</a>

//对应的控制器处理
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testString")
    public String testString(Model model){
        System.out.println("执行testString...");
        //模拟从数据库中查询user对象
        User user = new User();
        user.setUsername("美美");
        user.setPassword("123");
        user.setAge(20);
        //model存储数据
        model.addAttribute("user",user);
        return "success";
        /**
         * controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
         * 指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB-INF/pages/success.jsp
         */
    }
}

//成功跳转页面	success.jsp
<h3>执行成功</h3>
${user.username}		//美美
${user.password}		//123
${user.age}				//20

02 void

/*
   返回类型是void,默认会去请求user/testVoid.jsp
   请求转发:一次请求,不用编写项目的名称
   重定向:两次请求,地址栏会发生变化
   直接响应
*/
    @RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("执行testVoid...");
        //1 编写请求转发的程序
        //手动调用不会使用视图解析器
//        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

        //2 重定向相当于重新请求,不能直接访问WEB-INF下的文件
//        response.sendRedirect(request.getContextPath()+"/index.jsp");
//        response.sendRedirect("testString");

        //解决中文乱码
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");

        //直接对浏览器作出进行响应
        response.getWriter().print("你好");   //使用输出流

        return; //后面没有代码
    }

03 ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,可以在方法返回值返回这个对象,也可以通过视图解析器跳转到某个页面。

//返回ModeAndView对象
    @RequestMapping("/testModeAndView")
    public ModelAndView testModeAndView(){
        //1 创建ModeAndView对象
        ModelAndView mv = new ModelAndView();
        System.out.println("执行testModeAndView...");
        //模拟从数据库中查询user对象
        User user = new User();
        user.setUsername("泡泡");
        user.setPassword("456");
        user.setAge(20);
        //把user对象存储到mv对象中,底层也会把user对象存储到request域中
        mv.addObject("user",user);
        //跳转到哪个页面 --- 用视图解析器
        mv.setViewName("success");  //设置一个视图success.jsp
        return mv;  //返回字符串的底层源码也是使用ModeAndView
    }

1.2 转发和重定向

用的比较少,用不了视图解析器

//使用关键字的方式进行转发或重定向
    @RequestMapping("/testForwardOrRedirect")
    public String testForwardOrRedirect(){
        System.out.println("testForwardOrRedirect执行...");
        /*
            请求的转发 --- 不能再使用视图解析器,需要自己写路径
                关键字:forward
         */
//        return "forward:/WEB-INF/pages/success.jsp";

        /*
           重定向:(无法访问WEB-INF目录下文件)
               关键字:redirect
         */
        return "redirect:/index.jsp";  //没有加项目的名称,底层有实现
    }

1.3 ResponseBody 响应 json 数据

注意:有些文件不应该被前端控制器拦截

springmvc.xml
 <!--前端控制器,哪些静态资源不拦截-->
    <!-- 设置静态资源不过滤 -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
    <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

设置完毕,再引入js文件就不会有问题了。

  1. 发送ajax请求
需要引入jquery文件
<script>
        //页面加载,绑定点击事件
        $(function () {
           $("#btn").click(function () {
               //发生ajax请求
               $.ajax({
                   //编写json格式,设置属性和值
                   url:"user/testAjax",
                   contentType:"application/json;charset=utf-8",
                   data:'{"username":"张三","password":"123","age":30}',
                   dataType:"json", //服务器返回的数据类型
                   type:"post",     //请求方式
                   success:function (data) {    //成功的回调函数
                    //data:服务器端响应的json数据,进行解析
                   }
               });
           });
        });
    </script>
  1. 响应json格式数据
  • 发送过来的json数据,如果key值和javaBean里的属性值相同,则spring会帮你把json数据封装到对象中,需要引入一些jar包。
pom.xml
<!-- json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
//模拟异步请求和响应
    //使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端。
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){	//应该接受json封装好的user
        System.out.println("testAjax执行...");
        //客户端发生ajax请求,传的是json字符串,后台把json字符串封装到user对象中
        System.out.println(user);
        //响应:模拟查询数据库
        user.setUsername("哈哈");
        user.setAge(40);
        //响应数据---前端dataType:json --- > 还是要接受json数据dataType
        return user;    //会转成json串返回
    }

2 SpringMVC实现文件上传

  • 文件上传的必要前提:
    * A: form 表单的 enctype 取值必须是:multipart/form-data
    (默认值是:application/x-www-form-urlencoded)
    enctype:是表单请求正文的类型
    * B: method 属性取值必须是 Post
    * C: 提供一个文件选择域
  • 依赖jar包
    使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。
    commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。
 <!--文件上传-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

2.1 传统方式的文件上传

index.jsp
	<form action="user/fileUpload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"/> <br>
        <input type="submit" value="上传">
    </form>
//文件上传
    @RequestMapping("/fileUpload1")
    public String fileUpload1(HttpServletRequest request) throws Exception {  //解析request,从而拿到文件上传的选项
        System.out.println("文件上传...");
        //使用fileupload组件完成文件上传
        //1 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");//拿绝对路径
        //1.1判断路径是否存在
        File file = new File(path);
        if(!file.exists()){ //不存在则创建
            file.mkdirs();
        }
        //2 解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory(); //磁盘文件项工厂
        ServletFileUpload upload = new ServletFileUpload(factory);
        //2.1 解析request
        List<FileItem> items = upload.parseRequest(request);//文件项的集合
        //2.2 遍历
        for (FileItem item : items) {
            //进行判断,判断当前item对象是否是上传文件项
            if(item.isFormField()){
                //普通表单项
            }else {
                //3 上传文件项
                //3.1 获取上传文件的名称
                String filename = item.getName();
                //把文件名称设置为唯一值uuid
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid+"_"+filename;
                //3.2 完成文件上传
                item.write(new File(path,filename));
                //3.3 删除临时文件
                item.delete();
            }
        }
        return "success";
    }

2.2 springMVC的文件上传

  • 原理
    request经过前端控制器,调用文件解析器,解析后拿到上传文件的选项,传递给Controller的方法。在这里插入图片描述
  • 配置文件解析器
springmvc.xml
  <!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/><!--最大文件大小 10M-->
    </bean>
<form action="user/fileUpload2" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"/> <br>
    <input type="submit" value="上传">
</form>

//springMvc文件上传
    @RequestMapping("/fileUpload2")
    public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws Exception { //MultipartFile upload 名字与表单name一致
        System.out.println("springMvc文件上传...");
        //使用fileupload组件完成文件上传
        //1 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");//拿绝对路径
        //1.1判断路径是否存在
        File file = new File(path);
        if(!file.exists()){ //不存在则创建
            file.mkdirs();
        }
        //不需要自己解析了
        String filename = upload.getOriginalFilename(); //拿到文件名称
        //把文件名称设置为唯一值uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        //完成文件上传
        upload.transferTo(new File(path,filename));
        return "success";
    }

2.3 springmvc 跨服务器方式的文件上传

  • 在实际开发中,我们会有很多处理不同功能的服务器,分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
    例如:
    应用服务器:负责部署我们的应用
    数据库服务器:运行我们的数据库
    缓存和消息服务器:负责处理大并发访问的缓存和消息
    文件服务器:负责存储用户上传文件的服务器
  • 搭建环境(上个项目的基础上)
    1. 配置两个tomcat服务器,一个是用于文件上传,一个用来存放上传的文件。
    2. 导入开发需要的jar包
pom.xml
<!--跨服务器文件上传-->
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>
  • 代码
//springMvc跨服务器文件上传
    @RequestMapping("/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception { //MultipartFile upload 名字与表单name一致
        System.out.println("springMvc跨服务器文件上传...");
        //1 定义上传服务器路径
        String path = "http://localhost:9090/uploads/";

        //2 说明上传文件项
        String filename = upload.getOriginalFilename(); //拿到文件名称
        //把文件名称设置为唯一值uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;

        //3 完成文件跨服务器上传
        // 创建客户端对象
        Client client = Client.create();
        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);//如果path的最后没有/,那么在path和filename之间需要拼接+"/"+
        // 上传文件
        webResource.put(upload.getBytes());//通过字节方式上传

        return "success";
    }
  • bug
  1. 报405 Method Not Allowed错误
    部署存储文件的服务器tomcat时,需要修改端口号,和上传文件的tomcat区分开来,并且tomcat服务器默认是不可写操作,只允许读,所以在Tomcat web.xml文件中的servlet标签内加入:
    在这里插入图片描述

  2. returned a response status of 409 Conflict 错误
    原因是存放文件的服务器没有指定的上传文件存放目录,我们可以手动创建一个,记得是在:项目 — target — 项目名称 — uploads
    要进入target里面的文件夹,不能直接在target中创建,因为粗心导致创建文件夹路径不对,卡了很久。


3 SpringMVC 中的异常处理

  • 系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
    系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。
    在这里插入图片描述

  • 配置异常处理器

  1. 自定义异常类
//自定义异常类
public class SysException extends Exception {
    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SysException(String message) {
        this.message = message;
    }
}
  1. 编写异常处理器
//异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver {

    /**
     * 程序出现异常会调用一次处理器,执行这个方法
     * @param ex    Controller把异常抛出,ex就是当前抛出的异常对象SysException,我们可以使用ex获取提示信息
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        //1 获取到异常对象
        SysException e = null;
        if(ex instanceof SysException){
            e = (SysException)ex;   //强转成具体类型
        }else { //抛出的不是自定义的异常(其他异常)
            e = new SysException("系统正在维护...");
        }
        //方法的返回值是ModelAndView,可以跳转到页面
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());  //在跳转的错误页面可获取errorMsg
        mv.setViewName("error");    //找视图解析器,跳转到对应页面
        return mv;
    }
}
在springmvc.xml中配置,就像普通的bean
 <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"></bean>
  1. 控制器,会抛出异常
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testException")
    public String testException() throws SysException {
        System.out.println("testException执行...");
        try {
            int i = 1/0;    //模拟异常
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException("出现异常...");
        }
        return "success";
    }
}
  1. 出现异常跳转的error.jsp
    使用el表达式获取异常信息显示,这样在前端就不会直接打印异常信息,而是给出提示,我们可以在后端看到具体的异常信息。
 ${errorMsg}

4 SpringMVC 中的拦截器

  • Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
  • 区别:
    过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
    拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
    过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
    拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。

4.1 自定义拦截器

01 入门代码
先执行拦截器,放行后执行controller中方法,controller再跳转到success.jsp

  1. 编写拦截器类
//自定义拦截器
public class MyInterceptor implements HandlerInterceptor {
    //接口中的方法都实现了,但是也可以重写

    /**
     * 预处理:controller方法执行前
     * @param request
     * @param response
     * @param handler
     * @return  true:放行,执行下一个拦截器,如果没有则执行controller中的方法
     *          false:不放行,可以跳转到其他页面(提示...)
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor拦截器执行...");
        return true;
    }
}
  1. 配置拦截器
springmvc.xml
 <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体方法-->
            <mvc:mapping path="/user/*"/>
            <!--不拦截的方法,二者选其一
            <mvc:exclude-mapping path=""></mvc:exclude-mapping>-->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  1. controller
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testInterceptor")
    public String testInterceptor() {
        System.out.println("testInterceptor执行...");
        return "success";
    }
}

02 拦截器HandlerInterceptor接口中的方法

  • 三个方法的执行时机不同,可以用来实现不同的处理。
//自定义拦截器
//放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法
public class MyInterceptor implements HandlerInterceptor {
    //接口中的方法都实现了,但是也可以重写

    /**
     * 预处理:controller方法执行前
     * @return  true:放行,执行下一个拦截器,如果没有则执行controller中的方法
     *          false:不放行,可以跳转到其他页面(提示...)
     *
     * 可以做一些逻辑的判断,例如用户登录,如果没登录,直接跳登录页面
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor拦截器执行...前");
        //return false时:不放行,可以设置拦截器直接跳到其他页面做出响应
//      request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;  
    }

    /**
     * 后处理的方法:controller执行后,success.jsp执行前
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor拦截器执行...后");
        //拦截器指定跳转页面,则不会再跳success.jsp,但是success中的代码会执行
//        request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /** 全部执行完
     * success.jsp执行后,该方法会执行
     *
     * 可以用于释放资源
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor拦截器执行...最后");
        //success.jsp响应执行完了,不能再跳其他页面
    }
}

  • 可以配置多个拦截器,会按照拦截器链来执行
	<!--配置第二个拦截器-->
      <mvc:interceptor>
          <mvc:mapping path="/**"/>
          <bean class="cn.itcast.interceptor.MyInterceptor2"></bean>
      </mvc:interceptor>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值