SpringMVC02

响应数据呵结果视图

返回值分类

  • 返回值为字符串

    用于指定返回的逻辑视图名称;
    控制器代码:
        @RequestMapping("/test1")
        public String test1(String pname){
            System.out.println(pname);
            System.out.println("返回string类型测试");
            return "main";
        }
    
  • void类型(servlet的api操作)

    通常使用原始servlet处理请求时,返回该类型;
    控制器代码:
        @RequestMapping("/test2")
        public void test2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("返回void类型测试");
            request.getRequestDispatcher("/response/test1").forward(request,response);
        }
    
    
  • ModelAndView

    用于绑定参数和指定返回视图名称;
    控制器代码:
        @RequestMapping("/test3")
        public ModelAndView test3(ModelAndView modelAndView){
            modelAndView.addObject("aa","aa1");
            modelAndView.setViewName("main");
            return modelAndView;
        }
    

转发和重定向

  • forword请求转发

    控制器代码:
        @RequestMapping("/test4")
        public String test4(){
            System.out.println("我是请求转发");
            return "forward:/response/test1";
        }
    
  • redirect重定向

    控制器代码:
      @RequestMapping("/test5")
        public String test5(RedirectAttributes redirectAttributes,String pname){
            System.out.println("我是重定向");
           // redirectAttributes.addAttribute("pname",pname);
            redirectAttributes.addFlashAttribute("pname",pname);
            return "redirect:/response/test1";
        }
    
    //注意:重定向携带参数,需要使用对象RedirectAttributes,该对象提供两个方法封装参数addAttribute()和addFlashAttribute(),第一个方法参数会明文显示在浏览器地址栏,第二个方法参会会隐藏,使用第二种方法传参时,获取参数时需要加注解@ModelAttribute;
    

响应json数据

servlet中异步响应json数据:
String jsonStr = JSON.toJsonString(List<User>)
response.getWriter().write("{key:value,key:value....}");
(1)导入依赖
 <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
     <version>2.11.4</version>
 </dependency>
(2)编写代码
    @RequestMapping("/showFruit")
    @ResponseBody
    public  List<Fruit> showFruit(){
        List<Fruit> list = new ArrayList<>();
        for(int i=0;i<10;i++){
            Fruit fruit = new Fruit();
            fruit.setFname("apples"+i);
            fruit.setFname("好吃"+i);
            list.add(fruit);
        }
        System.out.println(list.size());
        return list;
    }

Rest风格编程

Rest风格URL规范介绍

  • restful介绍

    • RESTful架构,就是目前最流行的一种互联网软件架构风格。
  • restful优点

    • 结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
  • restful特性

    • 资源

      • 网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
    • 表现层

      • 把资源具体呈现出来的形式,叫做它的表现层 (Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
    • 状态转化

      • 每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
    • 传统请求url

    • Rest风格请求

PathVariable注解详解

  • 该注解用于绑定 url 中的占位符。例如:请求 url 中/annotation/test9/{id},这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是springmvc 支持 rest 风格 URL 的一个重要标志。
  • 属性:value:用于指定 url 中占位符名称。
    required:是否必须提供占位符

案例

构建页面发起请求

REST风格编程:
新增:
<form action="/annotation/person" method="post">
    用户名:<input name="userName" type="text">
    年龄:<input name="age" type="text">
    <input type="submit" value="提交">
</form>
修改:
<form action="/annotation/person" method="post">
    <input type="hidden" name="_method" value="PUT">
    用户名:<input name="userName" type="text">
    年龄:<input name="age" type="text">
    <input type="submit" value="提交">
</form>

删除:
<form action="/annotation/person/1" method="post">
    <input type="hidden" name="_method" value="DELETE">
    <input type="submit" value="提交">
</form>
查询:
<a href="/annotation/person/1">查询用户</a>

定义控制层执行器处理请求

   @RequestMapping(value = "person",method = RequestMethod.POST)
   public String addPerson(String userName,int age){
       System.out.println("新增用户:"+userName);
       return "main";
   }
   @RequestMapping(value = "person",method = RequestMethod.PUT)
   public String updatePerson(String userName,int age){
       System.out.println("修改用户:"+userName);
       return "main";
   }
   @RequestMapping(value = "person/{id}",method = RequestMethod.DELETE)
   public String deletePerson(@PathVariable(value = "id")int id){
       System.out.println("删除用户:id"+id);
       return "main";
   }
   @RequestMapping(value = "person/{id}",method = RequestMethod.GET)
   public String findPerson(@PathVariable(value = "id")int id){
       System.out.println("查询用户信息:id"+id);
       return "main";
   }

引入请求方式转换过滤器

 <filter>
        <filter-name>hiddenMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

SpringMVC中的父子容器解析

SpringMVC中的父子容器解析

  • Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean。

SpringMVC中的文件上传

文件上传的必要前提

  • form 表单的 enctype 取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)enctype:是表单请求正文的类型
  • method属性取值必须是Post
  • 提供一个文本选择域

文本上传原理分析

  • 当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:key=value&key=value&key=value;
    当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:每一部分都是 MIME 类型描述的正文;

SpringMVC上传文件

1、构建maven工程添加相关依赖

  <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
  </dependency>

2、编写 jsp 页面

<form enctype="multipart/form-data" method="post" action="/file/fileUpload">
    <input type="file" name="file">
    <input type="submit" value="上传">
</form>

3、编写控制器

   @RequestMapping("/fileUpload")
    public String fileUpload(MultipartFile file){
        File dest = new File("C:\\Users\\mwx\\Pictures\\"+file.getOriginalFilename());
        //文件上传
        try {
            file.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "main";
    }

4、配置文件解析器

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

文件下载

Spring文件下载使用内部工具类 ResponseEntity完成
制作文件下载控制器方法
@RequestMapping("/downloadFile")
public ResponseEntity<byte[]> downloadFile() throws Exception{
	String fileName = "2018年上半年绩效考核.xls";		
	String path = "C:\\upload\\";
	String newFileName = new String(fileName.getBytes("gbk"),"iso-8859-1");		
	File file = new File(path + fileName);		
	// 设置我们文件的响应头
	HttpHeaders header = new HttpHeaders();
	//指定输出的文件名称(硬编码以后的文件的名称)
	header.setContentDispositionFormData("attachment",newFileName);
    //设置我们的响应类型(MIME:text\html application\json text\xml image\jpeg)
	header.setContentType(MediaType.APPLICATION_OCTET_STREAM);        
    //利用SpringMVC的工具将我们指定的File对象中文件编译成字节数组
    return 
new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),header,HttpStatus.OK);
}	

SpringMVC中的异常处理(只能处理controller包含的异常,了解api)

项目开发中异常处理的方式介绍

  • 系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

异常处理的设计思路

  • 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。

异常处理步骤

1、编写异常类和错误页面

  @RequestMapping("/test2")
    public String test2(){
        System.out.println("模拟出现异常");
        int i = 10/0;
        return "main";
    }

2、自定义异常处理器

public class MyExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ex.printStackTrace();
        System.out.println("自定义异常处理");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

3、配置异常处理器

 <bean class="com.offcn.util.MyExceptionHandler"></bean>

SpringMVC中的拦截器使用(Filter 过滤器)

拦截器的介绍和作用

  • SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。—拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器和过滤器的区别

  • 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用
    在web.xml中的 url-pattern 标签中配置了/*之后,可以对所有要访问的资源拦截。
  • 拦截器是 SpringMVC 框架自己的,只有使用了SpringMVC框架的工程才能用。
    只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者js是不会进行拦截的。它也是 AOP 思想的具体应用。
    要求必须实现:HandlerInterceptor 接口。

自定义拦截器步骤

编写一个普通类实现 HandlerInterceptor 接口

public class MyIntercepter implements HandlerInterceptor {
    /**
     * 控制层执行器方法前的拦截器
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("我是控制层执行器方法前的拦截器");
        //校验用户是否登录
        HttpSession session = request.getSession();
        String pname=(String)session.getAttribute("pname");
        if(pname!=null){
            //当前用户已经登录,放行
            return true;
        }else{
            //当前用户未登录,拦截跳转到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return false;
        }
        //返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法

    }

    /**
     * 控制层方法返回时拦截器
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                    @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("我是控制层执行器方法返回时拦截器");
    }

    /**
     * 控制层方法结束后的拦截器
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                         @Nullable Exception ex) throws Exception {
        System.out.println("我是控制层执行器方法结束后的拦截器");
    }
}

2、配置拦截器

<!--springMVC配置文件中注册拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/file/login"/>
            <bean class="com.offcn.util.MyIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

拦截器注意事项

  • 拦截器放行

    • 如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)方法返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法。
  • 拦截器中方法说明及放行情况

    public class MyInterceptor2 implements HandlerInterceptor {
        /**
         * 控制层执行器方法前的拦截器(该方法是在控制层执行器方法前调用,当该方法返回结果为true则继续调用下一个拦截器,如果已经时最后
         * 一个拦截器,则调用控制层中的执行器方法;当该方法返回结果为false,则不会继续执行控制层执行器中的方法)
         * @param request
         * @param response
         * @param handler
         * @return
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("我是控制器方法前拦截器2");
            return true;
    
        }
    
        /**
         * 控制层方法返回时拦截器(该方法是控制层执行器方法执行之后,由DispatcherServlet在将结果响应给浏览器前调用的方法)
         * @param request
         * @param response
         * @param handler
         * @param modelAndView
         * @throws Exception
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               @Nullable ModelAndView modelAndView) throws Exception {
            System.out.println("我是控制层执行器方法返回时拦截器2");
        }
    
        /**
         * 控制层方法结束后的拦截器(该方法在请求业务处理执行完全结束之后由DispatcherServlet调用执行)
         * @param request
         * @param response
         * @param handler
         * @param ex
         * @throws Exception
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                    @Nullable Exception ex) throws Exception {
            System.out.println("我是控制层执行器方法结束后的拦截器2");
        }
    }
    
  • 拦截器的作用路径

      <!--拦截器注册-->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/><!--用于指定拦截的 url-->
                <mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
                <bean class="com.offcn.util.MyIntercepter"></bean>
            </mvc:interceptor>
        </mvc:interceptors>
    

拦截器案例(验证用户是否登录)

实现思路分析

  • 定义登录页面,并定义请求映射。
  • 判断用户名密码是否正确
  • 如果正确 向 session 中写入用户信息
  • 返回登录成功。
  • 拦截用户请求,判断用户是否登录
  • 如果用户已经登录。放行
  • 如果用户未登录,跳转到登录页面

案例

1、登录页面login.jsp定义:
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/file/login" method="post">
    用户名:<input type="text" name="pname">
    密码:<input type="text" name="password">
    <input type="submit" value="登录">
</form>
</body>
</html>
2、控制器实现:
    @RequestMapping("/login")
    public String login(String pname, String password, HttpSession session){
        System.out.println("登录校验成功");
        //将登录成功的用户名存放到session中
        session.setAttribute("pname",pname);
        return "main";
   }
3、拦截器实现:
 @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("我是控制层执行器方法前的拦截器");
        //校验用户是否登录
        HttpSession session = request.getSession();
        String pname=(String)session.getAttribute("pname");
        if(pname != null){
            //当前用户已经登录,放行
            return true;
        }else{
            //当前用户未登录,拦截跳转到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return false;
        }
        //返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
    }
4、注册拦截器:
<mvc:interceptor>
    <mvc:mapping path="/**"/><!--用于指定拦截的 url-->
    <mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
    <bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>
posted @ 2021-09-23 21:48  Lucky_龍  阅读(28)  评论(0)    收藏  举报