码迷,mamicode.com
首页 > 编程语言 > 详细

SpringMVC

时间:2020-06-14 19:05:38      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:字节   内容   ace   jsp   二进制流   commons   注销   风格   mes   

1、学习文档

老版学习地址

新版学习地址

 

2、MVC特点

  • 轻量级,简单易学

  • 高效,基于请求响应的MVC框架

  • 与Spring兼容性好,无缝结合

  • 约定优于配置

  • 功能强大:RESTful、数据验证、格式化、本地化、主题等

  • 简洁灵活

 

3、在idea中配置tomcat

  • 1、在idea上面的导航栏中点击运行环境,点击Edit Configurations

    技术图片

  • 2、进入Edit Configurations页面后,点击 +

    技术图片

  • 3、出现以下页面,下拉,点击more items,找到并点击 Tomcat Server

    技术图片

  • 4、进入Tomcat 的配置页面

    • 修改名字

      技术图片

    • 把要发布的项目添加到Tomcat Server中

      技术图片

 

4、SpringMVC执行原理

  • 中心控制器 DispatcherServlet

    作用是将请求分发到不同的处理器

  • springMVC的原理图

    技术图片

  • springMVC执行原理

    • 执行原理图

    技术图片

     

    • 1、DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心,用户发出请求,DispatcherServlet接受请求并拦截请求

      我们假设请求的url为 :

      http://localhost:8080/SpringMVC/hello

      如上url拆分成三部分:

      • 服务器域名

        http://localhost:8080
      • 部署在服务器上的web站点:SpringMVC

      • 控制器:hello

      通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。

    • 2、HandlerMapping为处理器映射,DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler

    • 3、HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器。

    • 4、HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等

    • 5、HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler

    • 6、Handler让具体的Controller执行

    • 7、Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView

    • 8、HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet

    • 9、DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名

    • 10、视图解析器(ViewResolver)将逻辑视图名传给DispatcherServlet

    • 11、DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图

    • 12、视图呈现给用户

 

5、HelloSpringMVC

  • 导入依赖

    <!--webmvc-->
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-webmvc</artifactId>
       <version>5.1.9.RELEASE</version>
    </dependency>
    ?
    <!--servlet-->
    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>2.5</version>
    </dependency>
    ?
    <!--jsp-->
    <dependency>
       <groupId>javax.servlet.jsp</groupId>
       <artifactId>jsp-api</artifactId>
       <version>2.0</version>
    </dependency>
  • 配置web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
    ?
       <!--1、注册DispatcherServlet-->
       <servlet>
           <servlet-name>springMVC</servlet-name>
           <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    ?
           <!--关联一个springMvc的配置文件-->
           <init-param>
               <param-name>contextConfigLocation</param-name>
               <param-value>classpath:springmvc-servlet.xml</param-value>
           </init-param>
    ?
           <!--启动级别-->
           <load-on-startup>1</load-on-startup>
    ?
       </servlet>
       <!--/ 匹配所有的请求;(不包括.jsp)-->
       <!--/* 匹配所有的请求;(包括.jsp)-->
       <servlet-mapping>
           <servlet-name>springMVC</servlet-name>
           <url-pattern>/</url-pattern>
       </servlet-mapping>
    ?
    </web-app>
  • 配置springmvc的配置文件:springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    ?
       <!--添加处理映射器-->
       <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
       <!--添加处理器适配器-->
       <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
       <!--添加试图解析器:DispatcherServlet给他的ModelAndView-->
       <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
           <!--前缀-->
           <property name="prefix" value="/WEB-INF/jsp/"/>
           <!--后缀-->
           <property name="suffix" value=".jsp"/>
       </bean>
    ?
    </beans>
  • 编写controller

    public class HelloController implements Controller {
       public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    ?
           //ModelAndView:模型和视图
           ModelAndView modelAndView = new ModelAndView();
           //封装对象
           modelAndView.addObject("msg","Hello,SpringMVC!");
           //封装要跳转的视图
           modelAndView.setViewName("hello");
           return modelAndView;
      }
    }
  • 把controller配置到springmvc的配置文件中

    <bean id="/hello" class="com.hmx.controller.HelloController"/>
  • 编写前端页面,注意页面位置,和视图解析器中对应

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
  • 启动tomcat,测试,先进入的是主页 index.jsp,修改路径,进入hello.jsp,结果如下:

    技术图片

  • 可能会遇到404错误

    • 原因

      1、查看控制台输出,看是不是缺少了什么jar包

      2、如果查看jar包存在,显示无法输出,就在idea的项目发布中添加lib依赖

    • 解决办法

      1、打开Project Structure

      2、点击Artifacts,看WEB-INF下有没有lib文件夹

      3、没有手动添加lib文件夹,并且把所有的jar包资源添加到目录下

 

6、注解实现

  • mvc注解详解

    • @Controller

      声明Spring类的实例是一个控制器

    • @ResponseBody

      和@Controller配合使用,不会被解析资源,直接返回字符串

    • @RestController

      上面那两个注解合成功能

    • @RequestMapping

      映射url到控制器类或一个特定的处理程序方法,可用于类或者方法上

      用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径

  • 注解修改HelloSpringMVC

    • springmvc-servlet.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"
            xmlns:mvc="http://www.springframework.org/schema/mvc"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            https://www.springframework.org/schema/mvc/spring-mvc.xsd">
      ?
         <!--自动扫描包-->
         <context:component-scan base-package="com.hmx.controller"/>
      ?
         <!--让SpringMVC不处理静态资源-->
         <mvc:default-servlet-handler/>
      ?
         <!--支持mvc注解驱动-->
         <mvc:annotation-driven/>
      ?
         <!--视图解析器-->
         <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
             <property name="prefix" value="/WEB-INF/jsp/"/>
             <property name="suffix" value=".jsp"/>
         </bean>
      ?
      </beans>
    • Controller

      @Controller
      public class HelloController {
      ?
         @RequestMapping("/hello")
         public String Hello(Model model){
      ?
             //通过model模型进行操作
             String result = "Hello,SpringMVC!";
             model.addAttribute("msg",result);
             //这样就可以进行页面跳转
             return "hello";
        }
      }
    • 测试可以运行

 

7、Restful风格

  • 概念

    Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

  • 功能

    • 资源:互联网所有的事物都可以被抽象为资源

    • 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。

      分别对应 添加、 删除、修改、查询

  • 传统方式操作资源和使用RESTful操作资源对比

    • 传统方式操作资源通过不同的参数来实现不同的效果,

      方法单一,只能用post 和 get

    • 使用RESTful操作资源可以通过相同的请求方式来实现不同的效果,

      如下:请求地址一样,但是功能可以不同!

    • 查询

      传统方式:查询,GET
      http://127.0.0.1/item/queryItem.action?id=1
      ?
      RESTful:http:查询,GET
      http://127.0.0.1/item/1
    • 新增

      传统方式:新增,POST
      http://127.0.0.1/item/saveItem.action
      ?
      RESTful:新增,POST
      http://127.0.0.1/item
    • 更新

      传统方式:更新,POST
      http://127.0.0.1/item/updateItem.action
      ?
      RESTful:更新,PUT
      http://127.0.0.1/item
    • 删除

      传统方式:删除,GET或POST
      http://127.0.0.1/item/deleteItem.action?id=1
      ?
      RESTful:删除,DELETE
      http://127.0.0.1/item/1
  • @PathVariable

    让方法参数的值对应绑定到一个URI模板变量上

    @Controller
    public class RestFulController {
    ?
      //映射访问路径
      @RequestMapping("/commit/{p1}/{p2}")
      public String index(@PathVariable int p1, @PathVariable int p2, Model model){
         
          int result = p1 + p2;
          //Spring MVC会自动实例化一个Model对象用于向视图中传值
          model.addAttribute("msg","结果:" + result);
          //返回视图位置
          return "test";  
    }  
    }
  • 使用@RequestMapping注解里的method属性指定请求类型

    • 用于约束请求的类型,可以收窄请求范围

      示例:映射访问路径,必须是POST请求

      @RequestMapping(value = "/hello",method = {RequestMethod.POST})
      public String index2(Model model){
        model.addAttribute("msg", "hello!");
        return "test";
      }
    • 方法级别的注解变体有如下几个:组合注解

      @GetMapping
      @PostMapping
      @PutMapping
      @DeleteMapping
      @PatchMapping

 

7、转发和重定向

  • 注意:重定向不可以定向到WEB-INF下的jsp

  • 使用ModelAndView---配置了视图解析器

    public class HelloController implements Controller {
       public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    ?
           ModelAndView modelAndView = new ModelAndView();
    ?
           modelAndView.addObject("msg","Hello,SpringMVC!");
    ?
           modelAndView.setViewName("hello");
           return modelAndView;
      }
    }
  • 使用SpringMVC的方式---配置了视图解析器

    • 转发的Controller

      @Controller
      public class HelloController {
      ?
         @RequestMapping("/hello")
         public String ModelTest1(){
             return "hello";
        }
      }
    • 重定向的Controller

      @Controller
      public class HelloController {
      ?
         @RequestMapping("/hello")
         public String ModelTest3(){
             return "redirect:/index.jsp";
        }
      }
  • 使用SpringMVC的方式---未配置视图解析器

    • 转发的Controller

      • 方式一

        @Controller
        public class HelloController {
        ?
           @RequestMapping("/hello")
           public String ModelTest1(){
               return "/WEB-INF/jsp/hello.jsp";
          }
        }
      • 方式二

        @Controller
        public class HelloController {
        ?
           @RequestMapping("/hello")
           public String ModelTest2(){
               return "forward:/WEB-INF/jsp/hello.jsp";
          }
        }
    • 重定向的Controller

      @Controller
      public class HelloController {
      ?
         @RequestMapping("/hello")
         public String ModelTest3(){
             return "redirect:/index.jsp";
        }
      }

 

8、解决乱码问题

  • 自定义过滤器

    • JavaWeb中的普通过滤器

    • 对POST请求的乱码解决不了

  • SpringMVC的过滤器

    • 在web.xml中配置编码格式

      <filter>
         <filter-name>encoding</filter-name>
         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
         <init-param>
             <param-name>encoding</param-name>
             <param-value>utf-8</param-value>
         </init-param>
      </filter>
      <filter-mapping>
         <filter-name>encoding</filter-name>
         <url-pattern>/*</url-pattern>
      </filter-mapping>
    • 有些极端情况下,这个过滤器对get的支持不好,解决办法如下:

      • 1、配置tomcat的编码

      • 2、使用通用过滤器

  • 通用过滤器

    /**
    * 解决get和post请求 全部乱码的过滤器
    */
    public class GenericEncodingFilter implements Filter {
    ?
       public void init(FilterConfig filterConfig) throws ServletException {
      }
    ?
       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    ?
           //处理response的字符编码
           HttpServletResponse myResponse=(HttpServletResponse) response;
           myResponse.setContentType("text/html;charset=UTF-8");
    ?
           // 转型为与协议相关对象
           HttpServletRequest httpServletRequest = (HttpServletRequest) request;
           // 对request包装增强
           HttpServletRequest myrequest = new MyRequest(httpServletRequest);
           chain.doFilter(myrequest, response);
    ?
      }
    ?
       public void destroy() {
      }
    }
    ?
    //自定义request对象,HttpServletRequest的包装类
    class MyRequest extends HttpServletRequestWrapper {
    ?
       private HttpServletRequest request;
       //是否编码的标记
       private boolean hasEncode;
       //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
       public MyRequest(HttpServletRequest request) {
           super(request);// super必须写
           this.request = request;
      }
    ?
       // 对需要增强方法 进行覆盖
       @Override
       public Map getParameterMap() {
           // 先获得请求方式
           String method = request.getMethod();
           if (method.equalsIgnoreCase("post")) {
               // post请求
               try {
                   // 处理post乱码
                   request.setCharacterEncoding("utf-8");
                   return request.getParameterMap();
              } catch (UnsupportedEncodingException e) {
                   e.printStackTrace();
              }
          } else if (method.equalsIgnoreCase("get")) {
               // get请求
               Map<String, String[]> parameterMap = request.getParameterMap();
               if (!hasEncode) { // 确保get手动编码逻辑只运行一次
                   for (String parameterName : parameterMap.keySet()) {
                       String[] values = parameterMap.get(parameterName);
                       if (values != null) {
                           for (int i = 0; i < values.length; i++) {
                               try {
                                   // 处理get乱码
                                   values[i] = new String(values[i]
                                          .getBytes("ISO-8859-1"), "utf-8");
                              } catch (UnsupportedEncodingException e) {
                                   e.printStackTrace();
                              }
                          }
                      }
                  }
                   hasEncode = true;
              }
               return parameterMap;
          }
           return super.getParameterMap();
      }
    ?
       //取一个值
       @Override
       public String getParameter(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           if (values == null) {
               return null;
          }
           return values[0]; // 取回参数的第一个值
      }
    ?
       //取所有值
       @Override
       public String[] getParameterValues(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           return values;
      }
    }

 

9、数据处理

  • 处理提交数据

    • 1、提交的域名称和处理方法的参数名一致

      //提交数据: http://localhost:8080/hello?name=Andy
      ?
      //处理:正常写即可
      public String ModelTest1(String name){
         System.out.println(name);
         return "hello";
      }
    • 2、提交的域名称和处理方法的参数名不一致

      //提交数据: http://localhost:8080/hello?username=Andy
      ?
      //处理:使用@RequestParam注解
      public String ModelTest1(@RequestParam("username") String name){
         System.out.println(name);
         return "hello";
      }
    • 3、提交的是一个对象

      //提交数据: http://localhost:8080/mvc04/user?name=Andy&id=1&age=33
      ?
      //处理:参数用对象,注意:如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null
      public String ModelTest1(User user){
         System.out.println(user);
         return "hello";
      }
  • 数据显示到前端

    • 1、通过ModelAndView

      可以存储数据的同时,还可以进行设置返回的逻辑视图,进行控制展示层的跳转

    • 2、通过ModelMap

      继承了LinkedMap,除了实现了自身的一些方法,同样也继承了LinkedMap的方法和特性

    • 3、通过Model

      只有寥寥几个方法,适合用于存储数据,简化了新手对于Model对象的操作和理解

 

10、Json

  • 概念

    Javascript Object Notation,JS对象标记,是一种轻量级的数据交换格式,采用文本格式来存储和表示数据,有效提升网络传输效率

  • 语法格式

    • 对象表示为键值对,数据由逗号分隔

    • 花括号保存对象

    • 方括号保存数组

  • Json和JavaScript

    • 关系

      Json是JavaScript对象的字符串表示法,它使用文本表示一个JS对象的信息,实际上是一个字符串

    • Json和Javascript的相互转换

      <script type="text/javascript">
      ?
         var user = {
             name: "洪梦霞",
             age: "24"
        };
      ?
         //Javascript转Json
         var str = JSON.stringify(user);
         console.log(str);
      ?
      //Json转Javascript
         var u = JSON.parse(str);
         console.log(u);
      ?
      </script>
  • Jackson

    • 导入依赖

      <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>2.10.2</version>
      </dependency>
    • 解决Json的乱码问题:在springMVC的配置文件中配置以下内容

      <!--Json乱码问题解决-->
      <mvc:annotation-driven>
         <mvc:message-converters register-defaults="true">
             <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                 <constructor-arg value="UTF-8"/>
             </bean>
             <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                 <property name="objectMapper">
                     <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                         <property name="failOnEmptyBeans" value="false"/>
                     </bean>
                 </property>
             </bean>
         </mvc:message-converters>
      </mvc:annotation-driven>
    • 测试

      • 1、直接把Java对象的toString结果输出

        @RestController
        public class HelloController {
        ?
           @RequestMapping("/j1")
           public String json_1(){
               User user = new User("洪梦霞",24);
               String str = user.toString();
               return str;
          }
        }
        ?
        /*
        结果为:
        User(name=洪梦霞, age=24)
        */
      • 2、使用Jackson的方法转换对象为json字符串

        @RestController
        public class JsonController {
        ?
           @RequestMapping("/j2")
           public String json_2() throws JsonProcessingException {
               User user = new User("洪梦霞", 24);
               return JacksonUtils.getJackson(user);
          }
        }
        ?
        /*
        结果为:
        User(name=洪梦霞, age=24)
        */
      • 3、使用Jackson的方法转换列表为json字符串

        @RestController
        public class JsonController {
        ?
           @RequestMapping("/j3")
           public String json_3() throws JsonProcessingException {
               ArrayList<User> users = new ArrayList<User>();
               User user1 = new User("洪梦霞1", 24);
               User user2 = new User("洪梦霞2", 24);
               User user3 = new User("洪梦霞3", 24);
               users.add(user1);
               users.add(user2);
               users.add(user3);
               return JacksonUtils.getJackson(users);
          }
        }
        ?
        /*
        结果为:
        [{"name":"洪梦霞1","age":24},{"name":"洪梦霞2","age":24},
        {"name":"洪梦霞3","age":24}]
        */
      • 4、使用Jackson的方法将日期转换为字符串

        //1、不处理,直接将日期转换成字符串
        @RestController
        public class JsonController {
        ?
           @RequestMapping("/j4")
           public String json_4() throws JsonProcessingException {
               ObjectMapper objectMapper = new ObjectMapper();
               Date date = new Date();
               return objectMapper.writeValueAsString(date);
          }
        }
        ?
        /*
        结果为:
        1585971952751(时间戳表示)
        */
        ?
        //2、利用SimpleDateFormat处理
        @RestController
        public class JsonController {
           
           @RequestMapping("/j4")
           public String json_4() throws JsonProcessingException {
               ObjectMapper objectMapper = new ObjectMapper();
        ?
               
               //设置不使用时间戳方式
         objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
               //自定义日期格式
               SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
               objectMapper.setDateFormat(dateFormat);
               Date date = new Date();
               return objectMapper.writeValueAsString(date);
          }
        }
        ?
        /*
        结果为:
        "2020-04-04 11:53:32"
        */
        ?
        //3、把时间转换这个处理成工具类
        public class JacksonUtils {
           
           public static String getJackson(Object object){
               return getJackson(object,"yyyy-MM-dd HH:mm:ss");
          }
        ?
           public static String getJackson(Object object,String dateFormat){
               ObjectMapper mapper = new ObjectMapper();
               mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
               SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
               mapper.setDateFormat(simpleDateFormat);
        ?
               try {
                   return mapper.writeValueAsString(object);
              } catch (JsonProcessingException e) {
                   e.printStackTrace();
              }
               return null;
          }
        }
        ?
        @RestController
        public class JsonController {
           
           @RequestMapping("/j4")
           public String json_4() throws JsonProcessingException {
               Date date = new Date();
               return JacksonUtils.getJackson(date, "yyyy-MM-dd HH:mm:ss");
          }
        }
        ?
        /*
        结果为:
        "2020-04-04 11:53:32"
        */
  • Fastjson

    • fastjson三个主要的类

      • JSONObject

        • 代表了json对象

        • 实现了Map接口,猜想JSONObject底层操作是由Map实现的

        • JSONObject对于json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size()、isEmpty()方法获取“键:值”对的个数和判断是否为空,其本质是通过Map接口并调用接口中的方法完成的

      • JSONArray

        • 代表json对象数组

        • 内部是由list接口中的方法来完成的

      • JSON

        • 代表JSONObject和JSONArray的转化

    • 依赖

      <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>1.2.60</version>
      </dependency>
    • 测试

      • 1、列表转换成Json字符串

        @RestController
        public class JsonController {
        ?
           @RequestMapping("/j5")
           public String json_5() {
               List<User> users = new ArrayList<User>();
               User user1 = new User("洪梦霞1", 24);
               User user2 = new User("洪梦霞2", 24);
               User user3 = new User("洪梦霞3", 24);
               users.add(user1);
               users.add(user2);
               users.add(user3);
               return JSON.toJSONString(users);
          }
        }
      • 2、Java对象和Json对象的相互转换

        @RestController
        public class JsonController {
        ?
           @RequestMapping("/j6")
           public String json_6() {
               User user1 = new User("洪梦霞", 24);
               //Java对象转Json字符串
               String userJson1 = JSON.toJSONString(user1);
               System.out.println(JSON.toJSONString(userJson1));
        ?
               //Json字符串转Java对象
               User user2 = JSON.parseObject(userJson1, User.class);
               System.out.println(user2);
        ?
               //Java对象转Json对象
               JSONObject jsonObject = (JSONObject) JSON.toJSON(user1);
               System.out.println(jsonObject);
        ?
               //Json对象转Java对象
               User user3 = JSON.toJavaObject(jsonObject, User.class);
               System.out.println(user3);
        ?
               return "hello,fastJson";
          }
        }

 

11、Ajax

  • 概念

    • Asynchronous JavaScript And Xml:异步的javaScript和xml请求

    • 一种用于创建更好更快以及交互性更强的Web应用程序的技术

  • 作用

    • 无需重新加载整个页面,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新

    • 传统的网页,想要更新内容或提交一个表单,都需要重新加载整个网页。

    • 使用Ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新

    • 使用Ajax,用户可以创建接近本地桌面应用的直接高可用、更丰富、更动态的Web用户页面

  • 使用Ajax可以:

    • 注册时,输入用户名自动检测用户是否存在

    • 登录时,提示用户名密码错误

    • 删除数据时,将行ID发送到后台,后台在数据库中删除,删除成功后,在页面DOM中将数据行也删除

    • ......

  • JQuery.ajax

    • 为什么要使用JQuery.ajax?

      • Ajax的核心是XMLHttpRequest对象(XHR)

        XHR为向服务器发送请求和解析服务器响应提供了接口

        能够以异步方式从服务器获取新数据

      • jQuery 提供多个与 AJAX 有关的方法

        通过 jQuery AJAX 方法

        能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON

        同时您能够把这些外部数据直接载入网页的被选元素中

      • jQuery 不是生产者,而是大自然搬运工

      • jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用

    • jQuery.ajax 参数详解

      jQuery.ajax(...)
           部分参数:
                 url:请求地址
                 type:请求方式,GET、POST(1.9.0之后用method)
             headers:请求头
                 data:要发送的数据
         contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
               async:是否异步
             timeout:设置请求超时时间(毫秒)
           beforeSend:发送请求前执行的函数(全局)
             complete:完成之后执行的回调函数(全局)
             success:成功之后执行的回调函数(全局)
               error:失败之后执行的回调函数(全局)
             accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
             dataType:将服务器端返回的数据转换成指定类型
               "xml": 将服务器端返回的内容转换成xml格式
               "text": 将服务器端返回的内容转换成普通文本格式
               "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
             "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
               "json": 将服务器端返回的内容转换成相应的JavaScript对象
             "jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
  • 注册提示效果实现

    • 1、配置web.xml和springMVC的配置文件

    • 2、Controller编写

      @RestController
      public class Controller {
      ?
         @RequestMapping("/a1")
         public String ajax3(String name,String pwd){
             String msg = "";
             //模拟数据库中存在数据
             if (name!=null){
                 if ("admin".equals(name)){
                     msg = "OK";
                }else {
                     msg = "用户名输入错误";
                }
            }
             if (pwd!=null){
                 if ("123456".equals(pwd)){
                     msg = "OK";
                }else {
                     msg = "密码输入有误";
                }
            }
             return msg; //由于@RestController注解,将msg转成json格式返回
        }
      }
    • 3、前端页面login.jsp

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
         <title>ajax</title>
         <!--导入jQuery-->
         <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
         <script>
      ?
             function a1(){
                 $.post({
                     url:"${pageContext.request.contextPath}/a1",
                     data:{‘name‘:$("#name").val()},
                     success:function (data) {
                         if (data.toString()==‘OK‘){
                             $("#userInfo").css("color","green");
                        }else {
                             $("#userInfo").css("color","red");
                        }
                         $("#userInfo").html(data);
                    }
                });
            }
             function a2(){
                 $.post({
                     url:"${pageContext.request.contextPath}/a1",
                     data:{‘pwd‘:$("#pwd").val()},
                     success:function (data) {
                         if (data.toString()==‘OK‘){
                             $("#pwdInfo").css("color","green");
                        }else {
                             $("#pwdInfo").css("color","red");
                        }
                         $("#pwdInfo").html(data);
                    }
                });
            }
      ?
         </script>
      </head>
      <body>
         <p>
            用户名:<input type="text" id="name" onblur="a1()"/>
             <span id="userInfo"></span>
         </p>
         <p>
            密码:<input type="text" id="pwd" onblur="a2()"/>
             <span id="pwdInfo"></span>
         </p>
      </body>
      </html>
    • 4、效果查看

      技术图片

  • Ajax异步加载数据

    • 1、User类

    • 2、Controller编写

      @RestController
      public class AjaxController {
      ?
         @RequestMapping("a1")
         public ArrayList<User> a1() {
      ?
             ArrayList<User> users = new ArrayList<User>();
             users.add(new User("hmx", 24));
             users.add(new User("wy", 24));
             users.add(new User("mw", 22));
             return users;
        }
      }
    • 3、前端页面编写

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
         <title>Title</title>
      ?
         <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
      ?
         <script>
             $(function () {
                 $("#btn").click(function () {
                     $.ajax({
                         url: "${pageContext.request.contextPath}/a1",
                         success: function (data) {
                             var html = "<>";
      ?
                             for (let i = 0; i < data.length; i++) {
                                 html += "<tr>" +
                                     "<td>" + data[i].name + "</td>" +
                                     "<td>" + data[i].age + "</td>" +
                                     "</tr>"
                            }
      ?
                             $("#content").html(html);
                        }
                    })
                })
            });
         </script>
      ?
      </head>
      <body>
      <input type="button" id="btn" value="查询用户">
      ?
      <table>
         <thead>
         <tr>
             <td>用户名</td>
             <td>年龄</td>
         </tr>
         </thead>
         <tbody id="content">
      ?
         </tbody>
      </table>
      ?
      </body>
      </html>
    • 4、效果查看

      • 未点击按钮前

        技术图片

      • 点击按钮后

        技术图片

12、拦截器

  • 概念

    • SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用

    • 只拦截访问的控制器方法,是AOP思想的具体应用,如果访问的是jsp/html/css/image/js是不会拦截的

  • 自定义拦截器

    • 1、配置web.xml和MVC的配置文件

    • 2、编写拦截器

      public class MyInterceptor implements HandlerInterceptor {
      ?
         //在请求处理的方法之前执行
         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
             System.out.println("程序执行前");
             //return true:运行进入下一个拦截器
        //return false:不允许通过,程序到此终止
             return true;
        }
      ?
         //这两个方法一般用于拦截器的日志输出
         //在请求处理的方法之后执行
         public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
             System.out.println("程序执行后");
        }
      ?
         //在DispatchServlet处理后执行,做请理工作
         public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
             System.out.println("清理");
        }
      }
    • 3、在MVC的配置文件中配置拦截器

      <!--配置拦截器-->
      <mvc:interceptors>
         <mvc:interceptor>
             <!--
                 /**:包括这个请求下的所有请求,路径及其子路径
                 /admin/*:拦截的是/admin/add之类的请求
                 /admin/**:拦截的是/admin/下的所有请求
             -->
             <mvc:mapping path="/**"/>
             <!--bean配置的就是拦截器-->
             <bean class="com.hmx.interceptor.MyInterceptor"/>
         </mvc:interceptor>
      </mvc:interceptors>
    • 4、编写Controller,接收请求

      @Controller
      @RequestMapping("/user")
      public class TestController {
      ?
         @RequestMapping("/main")
         public String main() {
             System.out.println("Controller中的方法执行了!");
             return "main";
        }
      }
    • 5、前端页面

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
         <title>interceptor</title>
      </head>
      <body>
      ?
      </body>
      </html>
    • 6、测试

      技术图片

  • 测试:登录验证判断:只有登录了的用户才能访问除了登录外的其他页面,未登录前只能访问登录页面

    • 1、编写登录页面login.jsp

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
         <title>登录</title>
      </head>
      <body>
      <form action="${pageContext.request.contextPath}/user/goLogin" method="post">
        账号:<input type="text" name="username"><br>
        密码:<input type="text" name="password"><br>
         <input type="submit" value="登录">
      </form>
      </body>
      </html>
    • 2、Controller处理请求

      @Controller
      @RequestMapping("/user")
      public class TestController {
      ?
         @RequestMapping("/main")
         public String main(){
             return "main";
        }
      ?
         @RequestMapping("/login")
         public String login(){
             return "login";
        }
      ?
         @RequestMapping("/goLogin")
         public String goLogin(String username, String password, HttpSession session, Model model){
             session.setAttribute("userInfo",username);
             model.addAttribute("username",username);
             return "main";
        }
      ?
         @RequestMapping("/Logout")
         public String logout(String username, String password, HttpSession session){
             return "login";
        }
      }
    • 3、编写欢迎页index.jsp

      未登录前点击主页按钮,进去主页main.jsp

      点击登录按钮进入登录页面

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
       <title>欢迎页面</title>
      </head>
      <body>
      <a href="${pageContext.request.contextPath}/user/main">主页</a>
      <a href="${pageContext.request.contextPath}/user/login">登录</a>
      </body>
      </html>
    • 4、编写主页main.jsp

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
         <title>主页</title>
      </head>
      <body>
      <h1>主页</h1>
      <h2>${username}</h2>
      <a href="/user/Logout">注销</a>
      </body>
      </html>
    • 5、编写用户登录拦截器

      public class LoginInterceptor implements HandlerInterceptor {
      ?
         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      ?
             HttpSession session = request.getSession();
      ?
             //判断何种情况下允许通过过滤器
             //1、需要允许进入登录页面
             if(request.getRequestURI().contains("login")){
                 return true;
            }
             //2、点击登录按钮时触发的goLogin事件也需要放行
             if(request.getRequestURI().contains("goLogin")){
                 return true;
            }
             //3、如果session里有值,说明已经有用户登录,允许进入主页
             if (session.getAttribute("userInfo") != null){
                 return true;
            }
      ?
             //判断何种情况下不允许进入主页
             request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
             return false;
        }
      }
    • 6、配置拦截器

      <mvc:interceptors>
         <mvc:interceptor>
             <mvc:mapping path="/**"/>
             <bean class="com.hmx.interceptor.LoginInterceptor"/>
         </mvc:interceptor>
      </mvc:interceptors>
    • 7、再次测试,未登录前点击index页面的主页按钮,不能访问主页

 

13、文件上传与下载

  • 准备工作

    • 前端要求

      • 将表单的method设置为POST

      • 将enctype设置为multipart/form-data

        表单中的 enctype 属性

        • application/x-www=form-urlencoded

          默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式

        • multipart/form-data

          这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码

        • text/plain

          除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件

    一旦设置了enctype为multipart/form-data,浏览器会采用二进制流的方式来处理表单数据

    SpringMVC为文件上传提供了直接的支持,用即插即用的MultipartResolver实现的

    SpringMVC使用Apache Commons FileUpload技术实现了一个MultipartResolver的实现类:CommonsMultipartResolver

  • CommonsMultipartFile 的 常用方法

    • String getOriginalFilename():获取上传文件的原名

    • InputStream getInputStream():获取文件流

    • void transferTo(File dest):将上传文件保存到一个目录文件中

  • 文件上传

    • 导入依赖

      <dependency>
         <groupId>commons-fileupload</groupId>
         <artifactId>commons-fileupload</artifactId>
         <version>1.4</version>
      </dependency>
      ?
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>servlet-api</artifactId>
         <version>2.5</version>
      </dependency>
    • 配置bean

      <!--文件上传配置-->
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
         <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
         <property name="defaultEncoding" value="utf-8"/>
         <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
         <property name="maxUploadSize" value="10485760"/>
         <property name="maxInMemorySize" value="40960"/>
      </bean>
    • 编写前端页面

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
       <title></title>
      </head>
      <body>
       <form action="/upload" enctype="multipart/form-data" method="post">
         <input type="file" name="file"/>
         <input type="submit" value="upload">
       </form>
      </body>
      </html>
    • Controller:方式一

      @Controller
      public class TestController {
         //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
         //批量上传CommonsMultipartFile则为数组即可
         @RequestMapping("/upload")
         public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
      ?
             //获取文件名 : file.getOriginalFilename();
             String uploadFileName = file.getOriginalFilename();
      ?
             //如果文件名为空,直接回到首页!
             if ("".equals(uploadFileName)){
                 return "redirect:/index.jsp";
            }
             System.out.println("上传文件名 : "+uploadFileName);
      ?
             //上传路径保存设置
             String path = request.getServletContext().getRealPath("/upload");
             //如果路径不存在,创建一个
             File realPath = new File(path);
             if (!realPath.exists()){
                 realPath.mkdir();
            }
             System.out.println("上传文件保存地址:"+realPath);
      ?
             InputStream is = file.getInputStream(); //文件输入流
             OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
      ?
             //读取写出
             int len=0;
             byte[] buffer = new byte[1024];
             while ((len=is.read(buffer))!=-1){
                 os.write(buffer,0,len);
                 os.flush();
            }
             os.close();
             is.close();
             return "redirect:/index.jsp";
        }
      }
    • Controller:方式二,采用file.Transto 来保存上传的文件

      @RequestMapping("/upload2")
      public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
      ?
        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
      }
        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);
      ?
        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
      ?
        return "redirect:/index.jsp";
      }
  • 文件下载

    • 步骤

      • 1、设置 response 响应头

      • 2、读取文件 -- InputStream

      • 3、写出文件 -- OutputStream

      • 4、执行操作

      • 5、关闭流 (先开后关)

    • 前端页面编写

      <a href="/download">点击下载</a>
    • Controller

      public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
        //要下载的图片地址
        String  path = request.getServletContext().getRealPath("/upload");
        String  fileName = "基础语法.jpg";
      ?
        //1、设置response 响应头
        response.reset(); //设置页面不缓存,清空buffer
        response.setCharacterEncoding("UTF-8"); //字符编码
        response.setContentType("multipart/form-data"); //二进制传输数据
        //设置响应头
        response.setHeader("Content-Disposition",
                "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
      ?
        File file = new File(path,fileName);
        //2、 读取文件--输入流
        InputStream input=new FileInputStream(file);
        //3、 写出文件--输出流
        OutputStream out = response.getOutputStream();
      ?
        byte[] buff =new byte[1024];
        int index=0;
        //4、执行 写出操作
        while((index= input.read(buff))!= -1){
            out.write(buff, 0, index);
            out.flush();
      }
        out.close();
        input.close();
        return null;
      }
    •  

     

SpringMVC

标签:字节   内容   ace   jsp   二进制流   commons   注销   风格   mes   

原文地址:https://www.cnblogs.com/LittleSkinny/p/13125881.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!