Java学习-SpringMVC

SpringMVC

  • MVC是模型(model)、视图(view)、控制器(Controller)的简写,是一种软件设计规范。
  • 是将业务逻辑、数据、显示分离的方式来组织代码。
  • MVC的作用是降低了视图与业务逻辑间的双向耦合。
  • MVC不是一种设计模式,MVC是一种架构模式。

1、回顾Servlet

  1. 创建springmvc普通的Maven项目;

  2. 添加Framework Support

    屏幕截图 2021-10-29 101323

  3. 创建HelloServlet

    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1、获取前端参数
            String method = req.getParameter("method");
            if (method.equals("add")) {
                req.getSession().setAttribute("msg","执行了add方法。");
            }
            if (method.equals("delete")) {
                req.getSession().setAttribute("msg","执行了delete方法。");
            }
            //2、调用业务层
            //3、视图转发或者重定向
            req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  4. 创建test.jsp

    <form action="/hello" method="get">
        <input type="text" name="method"/>
        <input type="submit">
        <h1>Test:${msg}</h1>
    </form>
    
  5. 添加Tomcat支持,并启动测试http://localhost:8080/hello?method=add

2、第一个SpringMVC

  1. 配置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-config.xml</param-value>
            </init-param>
            <!-- 启动级别、1 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  2. 在resources目录下编写springmvc-config.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"/>
    
        <!-- 视图解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
            <!-- 前缀 -->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!-- 后缀 -->
            <property name="suffix" value=".jsp"/>
        </bean>
    
        <bean id="/hello" class="com.ls.controller.HelloController"/>
    
    </beans>
    
  3. 编写HelloController

    public class HelloController implements Controller {
    
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            //ModelAndView 视图和模型
            ModelAndView view = new ModelAndView();
            //封装对象,放在ModelAndView中
            view.addObject("msg", "Hello SpringMVC");
            //封装要跳转的视图,放在ModelAndView中
            view.setViewName("hello");
            return view;
        }
    
    }
    
  4. 启动Tomcat测试

如果遇到404的情况:

无标题

3、理解SpringMVC执行流程(重点)

[https://www.bilibili.com/video/BV1aE41167Tu?p=5]

  • 确定导入spring-webmvc依赖
    • image-20211029112449604
  • 确定最后发的项目中Artifacts中也有相应的Jar包
    • image-20211029112621392
  1. 配置DIspatcherServlet(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">
    
        <!-- 配置DispatchServlet:这个是SpringMVC的核心;请求分发器;前端控制器 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- DispatcherServlet要绑定Spring的配置文件 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
            <!-- 启动级别、1 --><!-- 让他跟服务器一块启动 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!--
            SpringMVC中:/ 和 /* 的区别
            /:只匹配所有的请求,不会去匹配jsp页面
            /*:只匹配所有的请求,包括jsp页面
        -->
    
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  2. 配置Spring的配置文件(springmvc-servlet.xml)(以下三个是SpringMVC的核心三要素)

    • 处理器映射器

      <!-- 处理器映射器 -->
      <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
      
    • 处理器适配器

      <!-- 处理器适配器 -->
      <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
      
    • 视图解析器

      <!-- 视图解析器 模板引擎:Thymeleaf Freemarker-->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
          <!-- 前缀 -->
          <property name="prefix" value="WEB-INF/jsp/"/>
          <!-- 后缀 -->
          <property name="suffix" value=".jsp"/>
      </bean>
      
  3. 编写控制层

    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ModelAndView mv = new ModelAndView();
            //业务代码
            String result = "HelloSpringMVC";
            mv.addObject("msg", result);
            //视图跳转
            mv.setViewName("test");
            return mv;
        }
    }
    
  4. 由于使用了BeanNameUrlHandlerMapping映射器,所以需要注册Bean

    <bean id="/hello" class="com.ls.controller.HelloController"/>
    
  5. 确定test.jsp可以收到msg

    ${msg}
    

SpringMVC执行流程

4、注解开发

  1. 配置DispatcherServlet

    <?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">
    
        <!-- 配置DispatchServlet:这个是SpringMVC的核心;请求分发器;前端控制器 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- DispatcherServlet要绑定Spring的配置文件 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
            <!-- 启动级别、1 --><!-- 让他跟服务器一块启动 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!--
            SpringMVC中:/ 和 /* 的区别
            /:只匹配所有的请求,不会去匹配jsp页面
            /*:只匹配所有的请求,包括jsp页面
        -->
    
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  2. 配置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
            https://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
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
        <!-- 自动扫描包,让指定包下的注解生效 -->
        <context:component-scan base-package="com.ls.controller"/>
        <!-- 默认的资源过滤,让SpringMVC不在处理静态资源  .css/.js/.mp3等 -->
        <mvc:default-servlet-handler/>
        <!--支持mvc注解驱动 -->
        <mvc:annotation-driven/>
        <!-- 视图解析器-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
            <!-- 前缀(在视图解析其中,把所有的视图都存放在WEB-INF下,这样可以保证视图安全,因为客户端不能直接访问这个目录下的文件。) -->
            <property name="prefix" value="WEB-INF/jsp/"/>
            <!-- 后缀 -->
            <property name="suffix" value=".jsp"/>
        </bean>
    
    </beans>
    
  3. 创建Controller

    @Controller//自动被Spring扫描到
    public class HelloController {
    
        @RequestMapping("/hello")
        public String hello(Model model) {
            model.addAttribute("msg", "HelloSpringmvc......");
            return "hello";
        }
    }
    
  4. 在hello.jsp中用${msg}取出信息。

  5. 如果出现404,检查WEB-INF下是否创建lib目录,并把相关jar包导入。

    image-20211029201654444

使用SpringMVC必须配置的三大件:处理器映射器,处理器适配器,视图解析器

5、控制器Controller

  • 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
  • 控制器负责解析用户的请求并将其转换为一个模型。
  • 在Spring MVC中一个控制器类可以包含多个方法
  • 在Spring MVC中,对于Controller的配置方式有很多种

6、实现Controller

第一种Controller实现方式,实现Controller接口:

  1. public class ControllerTest1 implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ModelAndView view = new ModelAndView();
            view.addObject("msg", "ControllerTest1");
            view.setViewName("test1");
            return view;
        }
    }
    
  2. 在spring配置文件中注册Controller Test1

    <bean name="/t1" class="com.ls.controller.ControllerTest1"/>
    

注意:实现Controller接口定义控制器是比较老的办法;

​ 缺点是一个控制器只可以实现一个方法,如果需要多个方法则需要定义多个控制器,定义的方式比较麻烦。

第二种实现Controller方式是使用注解

@Controller注解类型用于声明Spring类的实例是一个容器

@Controller// 代表这个类会被Spring自动接管
//在这个类中的所有方法,如果返回值是String,并且有具体页面可以跳转,那么就会被视图解析器解析。
public class ControllerTest2 {

    @RequestMapping("/t2")
    public String test1(Model model) {
        model.addAttribute("msg", "ControllerTest2...");
        return "test1";//WEB-INF/jsp/test1.jsp
    }

}

开启包扫描

<!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.ls.controller"/>

7、RequestMapping

@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或者方法上。用于类上,表示类中的所有相应请求的的方法都已该地址作为父路径。

@Controller
@RequestMapping("/father")
public class ControllerTest3 {

    @RequestMapping("/test1")
    public String test1(Model model) {
        model.addAttribute("msg", "Controller中的test1()......");
        return "test1";
    }
}

访问路径:localhost:8080/father/test1

8、RestFul风格

以前的访问地址例如:localhost:8080/login?username=root&password=123

RestFul风格(以斜线分割):localhost:8080/login/username/root

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

@Controller
public class RestFulController {

    //原来的方式:http://localhost:8080/add?a=1&b=2
    @RequestMapping("/add")
    public String test1(int a, int b, Model model) {
        int result = a + b;
        model.addAttribute("msg", "结果为" + result);
        return "test1";
    }

    // RestFul风格:http://localhost:8080/sub/9/5
    @RequestMapping("/sub/{a}/{b}")
    public String test2(@PathVariable int a, @PathVariable String b, Model model) {
        String result = a + b;
        model.addAttribute("msg", "结果为" + result);
        return "test1";
    }

}

使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!

​ http://127.0.0.1/item/1查询,GET

​ http://127.0.0.1/item 新增,POST

​ http://127.0.0.1/item 更新,PUT

​ http://127.0.0.1/item/1 删除,DELETE

使用method属性指定请求类型

用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等

测试:增加一个方法

  • @RequestMapping(value = "/sub/{a}/{b}", method = RequestMethod.POST)
    public String test2(@PathVariable int a, @PathVariable int b, Model model) {
        int result = a - b;
        model.addAttribute("msg", "结果为" + result);
        return "test1";
    }
    
  • 使用浏览器地址栏访问默认是GET请求,会报错405。

    image-20211029225247952

  • 将method改为GET就可以正常执行了。

    @RequestMapping(value = "/sub/{a}/{b}", method = RequestMethod.GET)
    public String test2(@PathVariable int a, @PathVariable int b, Model model) {
        int result = a - b;
        model.addAttribute("msg", "结果为" + result);
        return "test1";
    }
    
  • image-20211029225453848

所有的地址栏请求默认都会是HTTP GET类型的。

方法级别的注解变体有如下几个:组合注解

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

@GetMapping是一个组合注解,平时用的会比较多。

他所扮演的是@RequestMapping(method=RequestMethod.GET)的一个快捷方式。

总结:

  1. 最大的好处:安全,在地址栏上别人不知道你传参数的具体含义,隐藏了程序里的一些东西。
  2. 是路径变得更加简介;
  3. 获得参数更加方便,框架会自动进行类型转换;
  4. 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法。

9、重定向和转发

通过SpringMVC来实现重定向和转发-无需视图解析器

测试前,将视图解析器注释掉。

@Controller
public class ModelTest1 {

    @RequestMapping("/m1/t1")
    public String test1(Model model) {
        model.addAttribute("msg", "ModelTest1执行了");
        //return "/WEB-INF/jsp/test1.jsp";//转发
        return "forward:/WEB-INF/jsp/test1.jsp";//转发
    }

    @RequestMapping("/m1/t2")
    public String test2(Model model) {
        model.addAttribute("msg", "ModelTest1执行了");
        return "redirect:/index.jsp";//重定向
    }

}

通过SpringMVC来实现重定向和转发-有视图解析器

重定向,一个新的地方不需要视图解析器,本质就是重新请求,所以注意路径问题。

@Controller
public class ResultSpringMVC2 {
   @RequestMapping("/rsm2/t1")
   public String test1(){
       //转发
       return "test";
  }

   @RequestMapping("/rsm2/t2")
   public String test2(){
       //重定向
       return "redirect:/index.jsp";
       //return "redirect:hello.do"; //hello.do为另一个请求/
  }

}

10、数据处理

处理提交数据

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

    提交数据:http://localhost:8080/hello?name=leishuai

    @RequestMapping("/hello")
    public String hello(String name){
       System.out.println(name);
       return "hello";
    }
    

    后台输出:leishuai

  2. 提交的域名称和处理方法的参数不一致

    提交数据:http://localhost:8080/hello?username=leishuai

    //从前端接收一个参数
    @RequestMapping("/t1")
    public String test1(@RequestParam("username") String name, Model model) {
        System.out.println("从前端接收的参数:" + name);
        model.addAttribute("msg", name);
        return "test1";
    }
    
  3. 提交一个对象

    创建一个User对象

    public class User {
    
        private int id;
        private String name;
        private int age;
    
    }
    

    提交数据:http://localhost:8080/user/t2?id=1001&name=zhangsan&age=20

    //从前端接收一个对象
    @RequestMapping("/t2")
    public String test2(User user) {
        System.out.println(user);
        return "test1";
    }
    

    提交的表单数据需要和实体类的属性名一致,参数使用对象即可。

    后台输出

    User(id=1001, name=zhangsan, age=20)
    

    如果提交的表单数据和实体类的属性不一致,就会出现null;

    http://localhost:8080/user/t2?id=1001&username=zhangsan&age=20

    User(id=1001, name=null, age=20)

11、数据显示到前端

第一种 : 通过ModelAndView

我们前面一直都是如此 . 就不过多解释

public class ControllerTest1 implements Controller {

    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        //返回一个模型视图对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","ControllerTest1");
        mv.setViewName("test");
        return mv;
    }
}

第二种 : 通过ModelMap

ModelMap

@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
    //封装要显示到视图中的数据
    //相当于req.setAttribute("name",name);
    model.addAttribute("name",name);
    System.out.println(name);
    return "hello";
}

第三种 : 通过Model

Model

@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
   //封装要显示到视图中的数据
   //相当于req.setAttribute("name",name);
   model.addAttribute("msg",name);
   System.out.println(name);
   return "test";
}

对比

就对于新手而言简单来说使用区别就是:

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

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

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

12、乱码问题

  1. <form action="/e/t1" method="GET">
        <input type="text" name="name"/>
        <input type="submit">
    </form>
    
  2. @Controller
    public class EncodingController {
    
        @RequestMapping("/e/t1")
        public String test1(String name, Model model) {
            System.out.println(name);
            model.addAttribute("msg", name);
            return "test1";
        }
    
    }
    
  3. image-20211030093140552

解决办法:

  • 在web.xml中配置SpringMVC的乱码过滤
<!--2、配置SpringMVC的乱码过滤-->
<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>
  • 或者导入自定义的乱码过滤器

    <!--自定义的乱码过滤器-->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>com.ls.controller.GenericEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    GenericEncodingFilter

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Map;
    
    /**
     * 解决get和post请求 全部乱码的过滤器
     */
    public class GenericEncodingFilter implements Filter {
    
        @Override
        public void destroy() {
        }
    
        @Override
        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);
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
    }
    
    //自定义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;
        }
    }
    
    

13、JSON

  • json是一种轻量级的数据交换格式,目前使用特别广泛;
  • 采用完全独立于编程语言的文本格式来存储和展示数据;
  • 简洁和清晰的层次结构使得json成为理想的数据交换语言;
  • 已于阅读和编写,同时也易于机器解析和生成,有效的提升网络传输效率。
<script>

    //编写一个JavaScript对象 ES6
    var user = {
        name: "吕布",
        age: 20,
        sex: "男"
    };

    //将js对象转换为json对象
    var json = JSON.stringify(user);
    console.log(json);
    console.log("-----------------")

    //将json对象转化为js对象
    var obj = JSON.parse(json);
    console.log(obj);
</script>

image-20211030102151308

13.1、JackSon

目前比较好的json解析工具

这里使用Jackson,需要导入它的jar包

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

编写测试类:

@Controller
public class UserController {

    @RequestMapping("/j1")
    @ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
    public String json1() throws JsonProcessingException {
        //Jackson ,ObjectMapper
        ObjectMapper mapper = new ObjectMapper();
        //创建一个对象
        User user = new User("张三",20, "男");
        String value = mapper.writeValueAsString(user);
        return value;
    }

}

输出发现乱码:

image-20211030104257325

13.2、Json乱码解决办法

在web.xml中添加:

<!-- 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>

image-20211030111125892

Json添加多个对象

@RequestMapping("/j2")
@ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
public String json2() throws JsonProcessingException {
    //Jackson ,ObjectMapper
    ObjectMapper mapper = new ObjectMapper();
    List<User> userList = new ArrayList<>();
    //创建多个对象
    User user = new User("张三1号",20, "男");
    User user2 = new User("张三2号",20, "男");
    User user3 = new User("张三3号",20, "男");
    User user4 = new User("张三4号",20, "男");
    User user5 = new User("张三5号",20, "男");
    userList.add(user);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);
    userList.add(user5);
    String result = mapper.writeValueAsString(userList);
    return result;
}

image-20211030111820517

13.3、Json返回时间对象

@RequestMapping("/j3")
@ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
public String json3() throws JsonProcessingException {
    //Jackson ,ObjectMapper
    ObjectMapper mapper = new ObjectMapper();
    Date date = new Date();
    String value = mapper.writeValueAsString(date);
    return value;
}

时间解析后的默认格式为:时间戳:Timestamp( 时间戳是自1970 年 1 月 1 日(00:00:00 GMT)以来的秒数。它也被称为 Unix 时间戳(Unix Timestamp))。image-20211030112230536

时间格式化方式一:自定义时间戳

@RequestMapping("/j3")
@ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
public String json3() throws JsonProcessingException {
    //Jackson ,ObjectMapper
    ObjectMapper mapper = new ObjectMapper();
    Date date = new Date();
    //自定义日期的格式
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    String value = mapper.writeValueAsString(dateFormat.format(date));//默认返回时间戳
    return value;
}

image-20211030112821352

时间格式化方式二:不使用时间戳

mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

封装一个Json工具类

public class JsonUtils {

    //方法重载
    public static String getJson(Object object) throws JsonProcessingException {
        return getJson(object, "yyyy-MM-dd hh:mm:ss");
    }

    //自定义时间戳
    public static String getJson(Object object, String dataFormat) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleDateFormat format = new SimpleDateFormat(dataFormat);
        mapper.setDateFormat(format);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}
//自定义JsonUtils转换时间戳
@RequestMapping("/j4")
@ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
public String json4() throws JsonProcessingException {
    Date date = new Date();
    return JsonUtils.getJson(date, "yyyy-MM-dd HH:mm:ss");
}

13.4、FastJson

  1. 导入依赖

    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.76</version>
    </dependency>
    
  2. 测试

    @RequestMapping("/j5")
    @ResponseBody//加了@ResponseBody就不会走视图解析器,会直接返回一个字符串
    public String json5() throws JsonProcessingException {
        List<User> userList = new ArrayList<>();
        //创建多个对象
        User user = new User("张三1号",20, "男");
        User user2 = new User("张三2号",20, "男");
        User user3 = new User("张三3号",20, "男");
        User user4 = new User("张三4号",20, "男");
        User user5 = new User("张三5号",20, "男");
        userList.add(user);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        return JSON.toJSONString(userList);
    }
    

14、Ajax

  1. 新建一个Module

  2. 添加web支持

  3. 配置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">
    
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <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>
    
    </web-app>
    
  4. 配置applicationContext.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">
    
        <!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
        <context:component-scan base-package="com.ls.controller"/>
        <!-- 开启注解支持 -->
        <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>
    
  5. controller

    @RestController//表示这整个类都不会走视图解析器
    public class AjaxController {
    
        @RequestMapping("/t1")
        public String test() {
            return "hello";
        }
    
    }
    
  6. 配置Tomcat服务器,部署项目。

  • 测试一:
@RequestMapping("/t3")
public List<User> test3() {
    List<User> userList = new ArrayList<>();
    userList.add(new User("张三",10, "男"));
    userList.add(new User("李四",10, "男"));
    userList.add(new User("王五",10, "男"));
    return userList;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax刷新</title>
    <script src="/static/js/jquery-3.6.0.min.js"></script>
    <script>
        $(function () {
            $("#btn").click(function () {
                $.post({
                    url:"/t3",
                    success: function (data) {
                        // console.log(data);
                        var html = "";
                        for (let i = 0; i < data.length; i++) {
                            html += "<tr>" +
                                    "<td>" + data[i].name +"</td>"+
                                    "<td>" + data[i].age +"</td>"+
                                    "<td>" + data[i].sex +"</td>"
                                "</tr>";
                        }
                        $("#content").html(html);
                    }

                })
            })
        });
    </script>
</head>
<body>

<input type="button" value="提交数据" id="btn">
<table>
    <tr>
        <td>姓名</td>
        <td>年龄</td>
        <td>性别</td>
    </tr>
    <tbody id="content">
        <!-- 数据从后台来 -->
    </tbody>
</table>

</body>
</html>

image-20211031151913878image-20211031151929903

  • 测试二:
@RequestMapping("/t4")
public String test4(String name, String pwd) {
    String msg = "";
    if (name != null) {
        if ("admin".equals(name)){
            msg = "OK";
        } else {
            msg = "名字不匹配";
        }
    }
    if (pwd != null) {
        if ("1234".equals(pwd)){
            msg = "OK";
        } else {
            msg = "密码有误";
        }
    }
    return msg;
}

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.min.js"></script>

        <script>
            function a() {
                $.post({
                    url: "/t4",
                    data: {"name": $("#name").val()},
                    success: function (data) {
                        if (data.toString() == "OK") {
                            $("#userInfo").css("color","green");
                        } else {
                            $("#userInfo").css("color","red");
                        }
                        $("#userInfo").html(data);
                    }
                });
            }

            function b() {
                $.ajax({
                    url: "/t4",
                    data: {"pwd": $("#pwd").val()},
                    success: function (data) {
                        console.log(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" οnblur="a()"/>
            <span id="userInfo"></span>
        </p>
        <p>
            密码:<input type="text" id="pwd" οnblur="b()"/>
            <span id="pwdInfo"></span>
        </p>


    </body>
</html>

image-20211031152122407image-20211031152140017image-20211031152206529image-20211031152232157

15、SpringMVC拦截器

实现HandlerInterceptor接口

public class MyInterceptor implements HandlerInterceptor {

    //return true;执行下一个拦截器放行
    //return false;不执行下一个拦截器
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("-------------处理之前----------------");
        return false;
    }

}
<!-- 拦截器配置 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.ls.config.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

测试:

@RestController
public class TestController {

    @RequestMapping("/t1")
    public String test1() {
        System.out.println("test1执行了");
        return "OK!";
    }

}

结果:

image-20211031154834774

return true:

image-20211031154940375image-20211031155025794

16、文件上传

  1. 导入依赖

    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    
  2. 文件上传配置

    <!-- 文件上传配置,id="multipartResolver"是固定的不能更改 -->
    <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>
    
  3. FileController

    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
        //获取文件名字
        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";
    }
    
  4. 测试的jsp

    <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
        <input type="file" name="file"/>
        <input type="submit" value="upload">
    </form>
    

文件下载:

@RequestMapping("/download")
public String downloads(HttpServletResponse response, HttpServletRequest request) throws Exception {
    //要下载的图片地址
    String path = request.getServletContext().getRealPath("/static");
    String fileName = "1.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、读取文件--输入流
    FileInputStream inputStream = new FileInputStream(file);
    //3、写出文件--输出流
    OutputStream outputStream = response.getOutputStream();

    byte[] buff = new byte[1024];
    int index = 0;
    //4、执行  写出操作
    while ((index = inputStream.read(buff)) != -1) {
        outputStream.write(buff, 0, index);
        outputStream.flush();
    }
    outputStream.close();
    inputStream.close();
    return "OK";

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值