zoukankan      html  css  js  c++  java
  • SpringMVC

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

       

  • 相关阅读:
    Sunnypig闯三角关
    送给圣诞夜的贺卡
    uva 1592(NEERC 2009 STL)
    uva 297(传递闭包 WF 1996)
    hdu 4190(二分)
    uva 3592 (MST, kruskal)
    uva 11997 (基础数据结构)
    hdu 2680 (Dijkstra)
    hdu 4568(状态压缩dp)
    hdu 4582 (树上的贪心)
  • 原文地址:https://www.cnblogs.com/LittleSkinny/p/13125881.html
Copyright © 2011-2022 走看看