• SSM框架速成3:SpringMVC


    本来以为写这篇文章是在省程序设计大赛之后,没想到因为疫情不断推后,一推就是推一个月,还不知道12月底能不能比赛呢!战线拉太长确实还是很累的,更何况连续两周都需要打icpc,我现在就没有很多的耐心一直去钻研那些很难的acm题,这几天就先高效的把SpringMVC给速成了。

    现阶段只是速成SSM框架,为的是服务外包大赛,很多底层的东西我都没有去细致的研究,只能尽可能的去理解,方便自己的记忆。

    速成了SpringMVC以后接下来整合一下SSM框架以后再速成SpringBoot,当然因为各种竞赛我的时间可能会被切的很碎…

    我这里的整个学习过程都是用的tomcat 9,自己可以慢慢去搭建一下环境,要保证startup.bat文件打开以后能够访问localhost,并且访问8080端口,只需要在网址栏输入:localhost:8080即可。

    可能遇到的问题:404报错
    解决方法:这个问题可能是电脑里面有别的进程在使用8080端口,我也遇到这种情况了,最后的解决方法是修改tomcat安装路径的conf文件夹下的server.xml的配置,我们只需要将里面的端口号改为其他别的进程没有使用的端口,我使用的是8081。

    何为MVC

    MVC是模型层(dao,service)、视图层(jsp)、控制器层(Servlet(转发,重定向))的简写,是一种软件设计规范。
    是将业务逻辑、数据和显示分离的方法来组织代码。
    MVC的主要作用是降低了视图和业务逻辑间的双向耦合。
    MVC不是一种设计模式,MVC是一种架构模式,当然不同的MVC存在差异。

    平时写的思路:
    (1)先写dao层连接数据库。
    (2)写service层去调用dao层去执行一些具体的业务。
    (3)写servlet层接收前端(jsp/html)的数据,两个重要概念:转发和重定向

    MVC框架通常要做的事情:
    (1)将URL映射到java类或java类的方法
    (2)封装用户提交的数据
    (3)处理请求——调用相关的业务处理——封装响应数据
    (4)将响应的数据进行渲染.jsp/html等表示层数据

    Spring MVC的原理

    这里我就不阐释太多SpringMVC的东西了,我实在是看不懂(之前关于Servlet的东西都没有好好学)。。。醉了醉了。就说一下他的原理,方便后面入门SpringMVC。

    原理:当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染试图结果,将结果返回给中心控制器,再将结果返回给请求者。

    具体的原理如图所示:
    在这里插入图片描述

    Hello SpringMVC

    这里看不懂很正常,硬着头皮看看自己能看懂多少,实在看不懂没事,接下来会讲一下springmvc的工作原理。

    1、新建一个module,添加web的支持
    2、确定导入了SpringMVC依赖
    3、配置web.xml,注册DispatcherServlet
    4、编写SpringMVC的配置文件,名称:springmvc-servlet.xml,这里的名称是按照官方文档来的。
    5、添加处理映射器
    6、添加处理器适配器
    7、添加视图解析器
    8、编写我们要操作的业务Controller,要么实现Controller接口,要么增加注解;需要返回一个ModelAndVier,装数据、装视图
    9、将自己的类交给SpringIOC容器,注册bean
    10、写要跳转的jsp页面,显示ModelansView存放的数据,以及我们的正常页面
    11、配置tomcat启动测试

    可能遇到的问题为访问出现404,排查步骤为:
    1、查看控制台输出,看一下是不是缺少了某些jar包
    2、如果jar包存在,显示无法输出,就在idea的项目发布中,添加lib依赖
    3、重启tomcat即可解决问题

    我这里就简单按照上面的步骤写段程序,开始的很多东西可能都不太能体会,学到后面再慢慢搞懂。

    步骤如下:
    (1)新建一个普通的module,结构如下(别把jsp的位置放错了,这应该要放在WEB-INF下的):
    在这里插入图片描述
    (2)在我们的web.xml中注册DispatcherServlet,配置代码如下:

    
    <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>springmvcservlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
            
            <init-param>
                <param-name>contextConfigLocationparam-name>
                <param-value>classpath:springmvc-servlet.xmlparam-value>
            init-param>
            
            <load-on-startup>1load-on-startup>
        servlet>
    
    
        
        
        
        <servlet-mapping>
            <servlet-name>springmvcservlet-name>
            <url-pattern>/url-pattern>
        servlet-mapping>
    
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    (3)在springmvc-servlet.xml,这是按照官方文档来进行命名的,内容如下:

    
    <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.wang.controller.HelloController"/>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    (4)定义java类HelloController实现Controller接口:

    package com.wang.controller;
    
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    //注意:这里我们先导入Controller接口
    public class HelloController implements Controller {
    
    
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            //ModelAndView 模型和视图
            ModelAndView mv = new ModelAndView();
    
    
            //封装对象,放在ModelAndView中。Model
            mv.addObject("msg","HelloSpringMVC!");
            //封装要跳转的视图,放在ModelAndView中
            mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
            return mv;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    (5)在封装好对象和要跳转的视图之后,就编写hello.jsp,如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>WXJtitle>
    head>
    <body>
    ${msg}
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行之后可以得到${msg},我们接着在运行的网址背后加上hello,结果发现会报错,警告为404,这是因为idea中,新建一个项目以后可能没有生成相关的lib,这里就需要我们手动的进行导入,导入方法如下:
    (1)打开Project Structure,打开Artifacts,选中springmvc-02:
    在这里插入图片描述
    (2)选中WEB-INF文件夹,点添加文件按钮,手动添加lib文件夹:
    在这里插入图片描述
    (3)选中lib文件夹,点击加号,进入库的导入:
    在这里插入图片描述
    (4)进入后把全部依赖都选上,大功告成。

    SpringMVC工作原理

    只能说非常感谢狂神老师,他写的很多东西确实很好理解,主要我觉得狂神老师大多数时候能够了解到我们普通的学生在做这些事情的事情会遇到的不理解的地方,有种理解自己的老师是一件很难得的事情。

    这是狂神老师给出的图示:
    在这里插入图片描述
    其中打虚线的内容是我们要写的要实现的内容,而打实线的内容则是SpringMVC内部给我们封装好的功能。

    简要分析执行流程
    1、DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心,用户发出请求,DispatcherServlet接收请求并且拦截请求。
    (1)假设请求的URL为:http://localhost:8081/SpringMVC/hello
    (2)如上URL拆解为三部分:

    http://localhost:8081表示服务器域名
    SpringMVC表示部署在服务器上的web站点
    hello表示控制器

    通过分析,如上URL表示为:请求位于服务器localhost:8081的SpringMVC站点的hello控制器。
    2、HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据URL查找Handler。
    3、HandlerExecution表示具体的Handler,其主要作用是根据URL查找控制器,比如上面的URL被查找控制器为:hello。
    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、最终将视图呈现给用户。

    现在重新通过这个图理解了原理之后,可以再把上面的代码给重新实现一遍,加深理解和体会。

    使用注解开发SpringMVC

    其实真实的开发是不会用上面那么多复杂的东西的,我们需要学习注解开发,代码将会非常简洁。

    注解开发的流程如下:

    1、在进行注解开发之前,我们需要新建module的普通maven项目,并且导入依赖包。

    <build>
            <resources>
                <resource>
                    <directory>src/main/javadirectory>
                    <includes>
                        <include>**/*.propertiesinclude>
                        <include>**/*.xmlinclude>
                    includes>
                    <filtering>falsefiltering>
                resource>
                <resource>
                    <directory>src/main/resourcedirectory>
                    <includes>
                        <include>**/*.propertiesinclude>
                        <include>**/*.xmlinclude>
                    includes>
                    <filtering>falsefiltering>
                resource>
            resources>
        build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    我感觉有时候依赖的问题总会出点小情况,自己也没有去系统学过maven的一些知识,干脆就把新建的springmvc-03项目里面的pom.xml和总工程的pom.xml都加入这个依赖,接着再更新一些maven即可。

    查看maven里面的依赖情况如下:
    在这里插入图片描述
    2、配置web.xml
    (1)web的版本要是最新版,只需要点击项目并且右键选中Add Framework support,直接选中web里面就有默认的4.0版本,就是最新版了,接着在File-Project Structure里面选中该项目,创建lib目录手动导入依赖(同上)。
    (2)注册Dispatcher
    (3)关联SpringMVC的关联文件
    (4)启动级别为1
    (5)映射路径为/,注意不要用/*,会报404的错误

    配置代码如下:

    
    <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>SpringMVCservlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
            
            <init-param>
                <param-name>contextConfigLocationparam-name>
                <param-value>classpath:springmvc-servlet.xmlparam-value>
            init-param>
            
            <load-on-startup>1load-on-startup>
        servlet>
    
    
        
        <servlet-mapping>
            <servlet-name>SpringMVCservlet-name>
            <url-pattern>/url-pattern>
        servlet-mapping>
    
    
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3、添加SpringMVC的配置文件
    在resource目录下添加springmvc-servlet.xml配置文件,配置形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:

    
    <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.wang.controller"/>
        
        <mvc:default-servlet-handler />
        
        <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    4、创建Controller
    在java包下新建package:com.wang.controller,新建Controller类为HelloController,这个类不需要继承某个类或者实现某个接口,只需要利用注解开发即可,配置的消息已经在前面弄好了,使用@Controller语句包含这个类即可。

    代码如下:

    package com.wang.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/HelloController")
    public class HelloController {
    
        //真实访问地址:项目名/HelloController/hello
        //这是因为在这个类之前也写了@RequestMapping并且指定了路径
        //那么在这个类之下的所有@RequestMapping指定路径都包含它
        //一般情况下自己创造的网址不是很多的时候,不使用类之前定义@RequestMapping,不然网址写的会挺长
        @RequestMapping("/hello")
        public String hello(Model model){
            //向模型中添加属性msg与值,可以在JSP页面中取出并渲染
            model.addAttribute("msg","Hello,SpringMVCAnnotation!");
            //WEB-INF/jsp/hello.jsp
            return "hello";//返回视图,会被视图解析器处理
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意
    (1)@Controller是为了让Spring IOC容器初始化时自动扫描到
    (2)@RequestMapping是为了映射请求路径,这里因为类和方法都有映射因此访问时加上的请求时/HelloController/hello
    (3)方法中声明Model类型的参数是为了把Action中的数据带到视图中

    5、创建视图层

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>WXJtitle>
    head>
    <body>
    ${msg}
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果如下:
    在这里插入图片描述
    步骤总结
    1、新建一个web项目
    2、导入相关的jar包
    3、编写web.xml,注册DispatcherServlet
    4、编写springmvc配置文件
    5、创建对应的控制类controller
    6、完善前端视图和controller之间的对应
    7、测试运行调试

    使用springmvc必须配置的三大件:
    处理器映射器、处理器适配器、视图解析器
    通常,只需要手动配置视图解析器,而另外两大件只需要开启注解驱动即可,省去大段的xml配置。

    Controller配置总结

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

    实现接口定义控制器是一种比较老的方法,缺点是一个控制器里面只有一个方法,而如果我们有多个方法的时候就需要定义多个Controller,过于复杂。

    使用注解@Controller开发
    1、@Controller注解类型用于声明Spring类的实例是一个控制器
    2、Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能够找到你的控制器,需要在配置文件中声明组件扫描:

    <context:component-scan base-package="com.wang.controller"/>
    
    • 1

    3、增加一个ControllerTest类,使用注解实现:

    //@Controller注解的类会自动添加到Spring上下文
    //使用了@Controller以后,代表这个类会被Spring托管
    //被这个注解的类中的所有方法,若返回值为String,并且有具体页面可以跳转,那么就会被视图解析器解析
    @Controller
    public class ControllerTest{
    	//映射访问路径
    	@RequestMapping("/t2")
    	public String index(Model model){
    		//SpringMVC会自动实例化一个Model对象用于向视图中传值
    		model.addAttribute("msg","ControllerTest");
    		//返回视图层的位置
    		return "test";
    		//接着只需要在WEB-INF下新建jsp目录,然后新建test.jsp,返回${msg}即可
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可以多写几个Test类,同样return “test”,把映射访问路径改一下,addAttribute方法的显示文字改一下,可以发现确实访问的页面不是同样的一个了。

    可以发现,多个请求都可以指向一个视图,放回的页面结果不一样,说明视图是被复用的——控制器和视图之间是弱耦合关系

    RestFul风格

    概念
    RestFul就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这种风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
    功能
    资源:互联网所有的事物都可以被抽象为资源。
    资源操作:使用POST、DELETE、PUT、GET,使用不同的方法对资源进行操作。
    分别对应添加、删除、修改、查询四个功能

    我们先来回顾一下以前的风格是怎样的,假设我们传入参数a和b,要求返回结果在最终的页面,我们使用注解开发的java类如下:

    @Controller
    public class Test{
    	@RequestMapping("/add")
    	public String test(int a,int b,Model model){
    		int res=a+b;
    		model.addAttribute("msg","结果为"+res);
    		return "test";
    	}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    最后我们访问网站所需要的网址为:
    http://localhost:8081/add?a=1&b=2

    最后肯定是可以返回我们想要的视图层的,但是很显然,这个网址并不是很好看。我们平时日常生活中都不会使用这样风格的网址的,因此引入了RestFul风格。

    我们将要让这个网址最终展现为:
    http://localhost:8081/add/a/b,我们可以随机修改网址中的a和b,最终的返回结果都是正确的。

    解决方法:
    1、对参数使用@PathVariable注解,这个注解会把参数解析成路径变量
    2、修改路径映射的方式,我们要把方法体中的参数传给网址进行处理,需要加上{}符号,即为:@RequestMapping(“/add/{a}/{b}”)

    代码为:

    package com.wang.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class RestFulController {
        @RequestMapping("/add/{a}/{b}")
        public String test(@PathVariable int a, @PathVariable int b, Model model){
            int res=a+b;
            model.addAttribute("msg","结果为"+res);
            return "test";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行页面如下,成功。
    在这里插入图片描述
    使用method属性指定请求类型
    用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET,POST,PUT,DELETE等等。

    现在测试一下,增加一个方法,注解改为:

    @RequestMappping(value="/hello",method=RequestMethod.POST)
    或者
    @RequestMappping(path="/hello",method=RequestMethod.POST)
    
    • 1
    • 2
    • 3

    但是我们最后会报405的错误,这个错误表示的是我们的方法有误,目标资源不支持请求行中的接收方法。

    这是因为使用的是浏览器地址栏进行访问,默认是使用GET请求,和POST的方法相悖。我们只需要把地址映射的注解的POST改为GET即可。

    但是我们每次无论用什么请求来发送表单数据,都可以修改地址映射的注解的最后一个单词,但是这样的注解有衍生的变体,更为简洁:

    @GetMapping()
    @PostMapping()
    @PutMapping()
    @DeleteMapping()
    
    • 1
    • 2
    • 3
    • 4

    RestFul风格的好处
    1、安全(原来的风格会暴露参数,比如网址最后a=1&b=2的方式)
    2、使路径变得更加简洁
    3、获得参数更加方便,框架会自动进行类型转换
    4、通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法。

    乱码问题解决

    乱码问题是我们在写Web程序无法避免的问题,比较常见的是中文乱码,先写一个简单的表单提交程序查看:
    1、在web包上面的web包下新建form.jsp(注意不是放在WEB-INF下),内容为:

    <%--
      Created by IntelliJ IDEA.
      User: 王雄俊
      Date: 2022/11/8
      Time: 15:22
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <form action="e/t1" method="post">
        <input type="text" name="name">
        <input type="submit">
    </form>
    
    </body>
    </html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注意我们的action里面的网址是不在前面加上’/‘的,这是因为本身网址默认最后都会有个’/‘,那么执行这个动作之后直接在这个默认的’/'后面加上跳转的网址即可。

    2、在java下新增一个EncodingController类,代码为:

    package com.wang.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PostMapping;
    
    @Controller
    public class EncodingController {
    
    	//注意要用PostMapping,因为我们在jsp代码中写了表单的提交方式是post
        @PostMapping("/e/t1")
        public String test1(String name, Model model){
    
            model.addAttribute("msg",name);//获取表单提交的值
    
            return "test";//跳转到test页面显示输入的值
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    最后我们运行出来一个简单的表单提交页面如下:
    在这里插入图片描述
    当我们输入WXJ或者数字的时候,最后能够完整的显示出来,没有产生乱码,但是当我们将输入的内容改为中文“我爱斯蒂芬库里”的时候,跳转出来的页面显示如下:
    在这里插入图片描述

    乱码问题的解决可以使用过滤器,步骤如下:
    1、在java的com.wang下新建一个filter包,新建EncodingFilter类,代码如下:

    package com.wang.filter;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    public class EncodingFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
    
            chain.doFilter(request,response);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2、在web.xml下配置这个过滤器,配置的过程很简单,加上如下代码即可:

    <filter>
            <filter-name>encodingfilter-name>
            <filter-class>com.wang.filter.EncodingFilterfilter-class>
        filter>
    
        <filter-mapping>
            <filter-name>encodingfilter-name>
            <url-pattern>/url-pattern>
        filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    但是这个方法有一个很奇怪的问题和很奇怪的解决。。。
    如此修改以后依旧不能访问,但是当我们把表单的请求方式以及注解的方式都改成get的方式,发现表单的传送数据是可以的,也就是说我们手写的这个方式有一定的缺陷,那就是不支持post的数据传输。

    实际上,SpringMVC已经给我们提供了一段配置文件,让我们解决乱码,只需要在web.xml下增加以下配置:

    <filter>
        <filter-name>encodingfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>utf-8param-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>encodingfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    接着重启tomcat,记得:当我们修改了xml配置文件以后,一定要重启tomcat,单独的重新发布信息并不管用。最后发现表单的post请求可以了。
    在这里插入图片描述
    当然了,在SpringMVC中的乱码情况会很多,这个解决方案有时候又在极端情况不支持get请求,有些解决方案甚至还需要修改tomcat的配置文件,这里就不做过多阐释了。
    对于乱码问题,需要平时多注意,在尽可能能设置编码的地方,都设置为统一编码UTF-8。

    什么是JSON

    现在是前后端分离的时代,简单来说:后端用来提供接口,提供数据;前端负责渲染后端的数据。

    那么我们就需要在前后端之间建立一个连接,让后端的数据能够传送到前端,我们如果直接传送一个对象过去,前端的负责人并不一定能那么快的理解这个对象的含义,因此用json来作为两端连接的桥梁。

    那么什么是JSON呢?
    1、JSON是一种轻量级的数据交换格式,目前使用特别广泛。
    2、采用完全独立于编程语言的文本格式来存储和表示数据。
    3、间接和清晰的层次架构使得JSON称为理想的数据交换语言。
    4、易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络的传输效率。

    我们可以利用json自带的两个方法,把后端的对象解析成字符串传送给前端,前端可以把这个字符串解析成对象方便自己的渲染。
    那么JSON的交互过程,我们利用代码例子能够很好的看懂:

    新建一个module,勾选支持web框架,在web下新建一个jsontest.html,内容为:

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    
        <script type="text/javascript">
            //编写一个JavaScript对象
            var user={
                name:"王雄俊",
                age:3,
                sex:"男"
            };
    
            //将js对象转化为json对象
            var json=JSON.stringify(user);
            console.log(json);
    
            //将json对象转换为JavaScript对象
            var obj=JSON.parse(json);
            console.log(obj);
        script>
    
    head>
    <body>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    接着我们打开任意一个浏览器查看,接着右键点击检查,查看控制台我们就你能够发现我们打印的两个东西了,一个是字符串,另外一个是对象。
    在这里插入图片描述

    Jackson的使用

    我们要实现的是让java生成json的对象发给前端。Jackson是很好的json解析工具。

    1、在使用json之前,需要导入它的jar包,同时由于我们需要写一个类,构造方式我们使用注解进行构造也就是@lombok,那么我们也需要导入lombok的jar包,只需要在pom.xml中配置下面:

    <dependencies>
            <dependency>
                <groupId>com.fasterxml.jackson.coregroupId>
                <artifactId>jackson-databindartifactId>
                <version>2.10.0version>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>1.18.10version>
            dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、在java上新建com.wang.pojo包,新建实体类User,设置好构造函数,这里使用了注解进行有参构造以及无参构造:

    package com.wang.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    //需要导入lombok,分别实现无参构造和有参构造
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String name;
        private int age;
        private String sex;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3、在com.wang下新建package,新建类UserController,这里的代码我们并不希望它走视图解析器,只需要返回一个字符串即可:

    package com.wang.controller;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.wang.pojo.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class UserController {
        @RequestMapping("/j1")
        @ResponseBody //加上这个注解以后,它就不会走视图解析器,而是直接返回一个字符串
        public String test1() throws JsonProcessingException {
    
            //用Jackson的ObjectMapper创建一个对象
            ObjectMapper mapper=new ObjectMapper();
    
            //创建一个对象
            User user = new User("王雄俊",20,"男");
    
            String str=mapper.writeValueAsString(user);
    
            return str;
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    那么最后运行完以后的结果是这样的:
    在这里插入图片描述
    这样的形式就是JSON实现的类转化为字符串以后的格式,也就是用{}括起来的,里面的每一个元素都是“元素”:值的格式,但是这里显示出来的结果是乱码的,一种方法是在@RequestMapping上配置参数的编码方式,即:

    @RequestMapping(value="/j1",produces="application/json;charset=utf-8")
    
    • 1

    重新发布以后,刷新页面查看:
    在这里插入图片描述

    但是每次都使用这个方法未免太过于复杂,而Spring提供了通用的解决乱码的方法,这样就可以不用每次都去处理了!
    我们可以在SpringMVC的配置文件上添加一段消息SpringHttpMessageConverter转换配置:

    
        <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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    最后记得要重启tomcat,而不是重新发布,因为修改了配置文件。

    最后显示和上面一样。(当然这一切的过程都别忘了lib依赖,前面讲过的,否则会报错)。

    那么我们接下来看看如果传入JSON的是一个集合,JSON会怎样处理它并且返回字符串的?
    写一个新的方法如下:

    @RequestMapping("/j2")
        @ResponseBody //加上这个注解以后,它就不会走视图解析器,而是直接返回一个字符串
        public String test2() throws JsonProcessingException {
    
            //用Jackson的ObjectMapper创建一个对象
            ObjectMapper mapper=new ObjectMapper();
    
            //新建一个List对象
            List<User> userList=new ArrayList<>();
    
            //创建一个对象
            User user1 = new User("王雄俊",20,"男");
            User user2 = new User("余歌星",20,"男");
            User user3 = new User("库里",20,"男");
            User user4 = new User("阿耶莎",20,"男");
    
            userList.add(user1);
            userList.add(user2);
            userList.add(user3);
            userList.add(user4);
    
            String str=mapper.writeValueAsString(userList);
    
            return str;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    重新发布一下,访问t2,最后显示:
    在这里插入图片描述
    这里最外面的中括号就是指代了这个集合List。

    我们再来试试JSON如何把时间对象处理成字符串的?
    新增方法test3,方法体内容如下:

    @RequestMapping("/j3")
        @ResponseBody //加上这个注解以后,它就不会走视图解析器,而是直接返回一个字符串
        public String test3() throws JsonProcessingException {
    
            //用Jackson的ObjectMapper创建一个对象
            ObjectMapper mapper=new ObjectMapper();
    
            Date date = new Date();
    
            String str=mapper.writeValueAsString(date);
            return str;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    访问结果:
    在这里插入图片描述当我们每次都刷新这个网页的时候,这个数字会不停的跳动,然而这里显示的却不是我们所熟知的时间,这里返回的是:时间戳Timesstamp。那么我们该如何处理呢?
    自定义日期的格式,方法体内容修改为:

    ObjectMapper mapper=new ObjectMapper();
    
    Date date = new Date();
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.format(date);
    String str=mapper.writeValueAsString(sdf.format(date));
    return str;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    但是我建议上面的代码不要这么写,学过设计模式的同学都知道,这样写代码的复用性特别差,每次要写一个新的方法都要用ObjectMapper,造成代码的冗余,我们最好的方法就是自己再新建一个包utils,然后在下面自己写一个Utils类,然后写抽象方法。
    当我们要显示字符串的时候,只需要传参数进去就行。而当向上面的例子,有些需要修改SimpleDateFormat的格式,有些不需要,然而方法是可以重用的,这是java的特性,这样就能写出更高质量的代码了!这里就不做展示了。

  • 相关阅读:
    Docker构建Springboot项目,并发布测试
    Kubernetes---使用 Helm 安装部署 Dashboard 仪表盘
    springcloud22:sentinal的使用
    辣子鸡丁的家常做法 辣子鸡丁怎么做
    k8s ingress基础
    MySQL主从复制
    AtCoder Beginner Contest 228(A-Ex)
    5. 堪比JMeter的.Net压测工具 - Crank 实战篇 - 接口以及场景压测
    C++二分查找算法:找到 Alice 和 Bob 可以相遇的建筑
    分片架构设计技巧
  • 原文地址:https://blog.csdn.net/m0_52380556/article/details/127084037