SpringMVC复习——B站

1 常识

ssm:spring+springmvc+mybatis MVC三层架构

MVC:将业务逻辑、显示、数据分离
模型model(dao,service,负责底层数据库的连接和增删改查操作)
视图view(jsp/html,展示数据)
控制器controller(servlet,获取请求和返回响应)

POJO:实体类,包含这个实体的所有属性
VO:视图层对象,用于转化请求中的参数到对象中去,仅仅包含view层所需属性,相当于POJO的精简版
DTO:数据传输对象,用于存储service层所需的参数

接下来的学习方向:springmvc-vue-springboot-springcloud-linux

重点:springmvc的执行流程!!!

springmvc优点:
1 方便利用spring其他功能
2 自动绑定输入,正确转换数据类型
3 内置校验器
4 多种视图技术
5 使用xml配置文件

1.1 回顾jsp/servlet

转发和重定向

转发的特点:
1.地址栏不发生变化,显示的是上一个页面的地址
2.请求次数:只有1次请求
3.根目录:http://localhost:8080/项目地址/,包含了项目的访问地址
4.请求域中数据不会丢失
转发使用:request.getRequestDispatcher("/地址").forward(request, response);

重定向的特点:
地址栏:显示新的地址
请求次数:2次
根目录:http://localhost:8080/ 没有项目的名字
请求域中的数据会丢失,因为是2次请求

结论:如果要保留请求域中的数据,使用转发,否则使用重定向。无论转发或重定向后续的代码都会执行。

  1. 新建空白Maven工程,并添加框架支持:JaveWeb
  2. 导入相关依赖
      <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
    
  3. 创建一个servlet类
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 获取前端参数
            String method = req.getParameter("method");
            if("add".equals(method)){
                req.getSession().setAttribute("msg","do add");
            }
            if("delete".equals(method)){
                req.getSession().setAttribute("msg","do delete");
            }
            // 调用业务
    
            // 转发或重定向
            req.getRequestDispatcher("/WEB-INF/jsp/doMethod.jsp").forward(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  4. 创建对应页面
    注意:如果需要保证用户不可见,需要放在WEB-INF下面
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  5. 配置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"
             metadata-complete="true">
    
        <display-name>Welcome to Tomcat</display-name>
        <description>
            Welcome to Tomcat
        </description>
        
        <servlet>
            <servlet-name>hello</servlet-name>
            <servlet-class>com.xiaopi3.HelloServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    
        <session-config>
            <session-timeout>15</session-timeout>
        </session-config>
    </web-app>
    

2 springmvc

简单易学,高效,基于请求和响应,约定优于配置

功能强大,支持RESTful风格,数据验证,格式化,本地化,主题

围绕DispatcherServlet设计,可以将请求发送给不同的处理器(spring2.5后使用java5可以使用注解controller声明方式)

以请求为驱动

2.1 QuickStart(原理讲解,实际中不使用该步骤)

可能遇到的问题:
1.控制台输出显示缺少jar包(典型的,缺少请求分发器)
2 查看idea的项目结构中的artifact中的WEB-INF下是否有lib库,没有则手动添加,并导入所有jar包
3 重启tomcat

执行步骤:

  1. 浏览器发送请求给DispatcherServlet
  2. DispatcherServlet接收请求,给HandlerMapping去解析请求,寻找对应的HandlerExecution
  3. 找到HandlerExecution后,返回给DispatcherServlet,DispatcherServlet再去调用HandlerAdapter去执行该HandlerExecution,HandlerExecution中包装的就是Controller层的控制器类,执行过程中控制层会调用业务层,最终返回一个ModelAndView给HandlerAdapter
  4. HandlerAdapter拿到ModelAndView给DispatcherServlet,DispatcherServlet调用视图解析器ViewResolver,解析出数据和目标视图页面
  5. 跳转到终页面并插入数据

步骤:
1 编写跳转视图myhello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <body>
  ${msg}
  </body>
</html>

2 配置web.xml,装在请求分发器,地址映射,初始化配置(加载springmvc的配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
<!--核心配置:请求分发器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--    绑定spring配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
<!--    启动级别:1,表示tomcat服务后就启动-->
        <load-on-startup>1</load-on-startup>
    </servlet>
<!--请求映射:注意!这里/和/*有区别!前者只匹配请求,后者匹配请求+jsp页面-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

注意:请求映射里的/和/*区别很大!
/:只转发给请求分发器动作请求,不转发文件请求
/*:转发所有请求
由于请求分发器会自动拼接动作请求,并且最后加上jsp后缀,所以使用/*会导致无限循环!

如果是过滤器,url-pattern必须为/*才行
如果想看过滤器过滤了什么请求:String url = ((HttpServletRequest) request).getRequestURI();

3 配置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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    装配处理器映射器,bean名称映射器会去在beans中寻找匹配的bean名字-->
    <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>

    <bean id="/hello" class="com.xiaopi3.controller.HelloController"/>

</beans>

注意:如果采用的是实现接口的方式实现控制器,则处理器映射器处理器控制器不用显示写,默认有。
4 配置controller类

public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();

        // 业务代码
        String result = "hahahah";
        mv.addObject("msg",result);
        // 视图跳转
        mv.setViewName("myhello");// 会被视图解析器拼接成/WEB-INF/myhello.jsp
        return mv;
    }
}

5 启动tomcat部署项目,请求/hello地址发现显示正常

2.2 QuickStart

注意:可以添加一下打包过滤文件:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

https://www.cnblogs.com/dflmg/p/6393416.html
步骤:

  1. 配置web.xml(基本不用变,每次写都直接copy即可),同上节一样
  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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
">

<!--    包扫描可以实现启用注解(annotation-config),并且可以实现自动装配bean-->
    <context:component-scan base-package="com.xiaopi3.controller"/>
<!--    过滤静态资源请求,交由web容器默认servlet去处理-->
    <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>
  1. 新建控制器类:com.xiaopi3.controller下,该类包含控制器和映射器注解!!
@Controller // 注意:该控制器注解会被视图解析器解析,如果是@RestController则直接返回到前端,不解析!!
@RequestMapping("/to") // 一级地址
public class HelloController {

    // 二级地址
    @RequestMapping("/hello")
    public String hello(Model model){
        // 封装数据
        model.addAttribute("msg","my first annotation springmvc!");
        return "hello"; // 会被视图解析器处理,该字符串会作为视图名称
    }
}
  1. 新建jsp页面(对应于return字符串中的,被视图解析器组合后为:/WEB-INF/jsp/hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
${msg}
</body>
</html>

注意:如果碰到包找不到的报错,看一下上一节开头的提示
注意:@Controller@RestController的区别:前者注解会被视图解析器解析,后者则直接返回到前端,不解析!!

2.3 总结

springmvc中必备三大项:处理器映射器,处理器适配器,视图解析器,其中,前两者被:annotation-driver干掉了,只需配置最后一个,并开启注解驱动!

3 controller详解

控制器可以通过两种方式实现:通过实现接口Controller返回ModelAndView(不推荐),通过注解!
负责解析用户请求,并处理成模型

3.1 实现接口

配置springmvc-servlet.xml,该方式无需显示装配处理器映射器和处理器控制器
配置控制器映射类+视图解析器即可!

<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.xiaopi3.controller.HelloController"/>

编写控制器

public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();
        String result = "hahahah";
        mv.addObject("msg",result);
        mv.setViewName("myhello");// 会被视图解析器拼接成/WEB-INF/myhello.jsp
        return mv;
    }
}

总结:该方法以及不推荐使用,因为一个类只能映射一个请求,当请求过多,需要写很多类

3.2 注解方式

配置springmvc-servlet.xml (注意,最好不要加中文注释!有可能报编码异常!!)
配置扫描包+视图解析器即可

<context:component-scan base-package="com.xiaopi3.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

新建控制器类:com.xiaopi3.controller下,该类包含控制器和映射器注解!!
加上@Controller@RequestMapping即可

@Controller // 注意:该控制器注解会被视图解析器解析,如果是@RestController则直接返回到前端,不解析!!
@RequestMapping("/to") // 一级地址
public class HelloController {
    // 二级地址
    @RequestMapping("/hello")
    public String hello(Model model){
        // 封装数据
        model.addAttribute("msg","my first annotation springmvc!");
        return "hello"; // 会被视图解析器处理,该字符串会作为视图名称
    }
}

3.3 RESTful风格

一种资源定位和操作的风格,简洁、高效、安全
所有参数传递都采用/进行分割,类似于下面这种:
在这里插入图片描述
采用不同的请求方式来区分

对应的Controller类如下:

原始风格:

@RequestMapping("/add")
public String add(int a,int b,Model model){
   int res = a+b;
   model.addAttribute("msg","结果为:"+res);
   return "hello";
}

请求地址:/add?a=1&b=2

RESTful风格:

@RequestMapping("/add/{a}/{b}")
public String add2(@PathVariable int a,@PathVariable int b,Model model){
    int res = a+b;
    model.addAttribute("msg","结果为:"+res);
    return "hello";
}

请求地址:/add/4/6
改动两个地方:1. 地址栏通过{x}获取变量x的值;2. 参数列表通过@PathVariable绑定地址变量即可

同时可以指定请求方式:@RequestMapping(path="/add/{a}/{b}",method=RequestMethod.GET)
同时上面这种请求又可以简化:@GetMapping("/add/{a}/{b}"),POST|DELETE|PUT|PATCH都有这种简化

3.4 结果跳转方式

1 使用ModelAndView对象,可以设置view名称,跳转到指定页面,经过视图解析器
2 使用servlet api:request重定向和resp转发,方法内依旧能获取req和res(不推荐),不经过视图解析器
3 使用springmvc转发和重定向,不经过视图解析器,底层依旧是servlet api,(可以去掉视图解析器配置)需要写全jsp文件路径名称!

// servlet api 重定向
@RequestMapping("/add")
public String add2(HttpServletRequest req, HttpServletResponse resp){
    req.getRequestDispatcher("WEB-INF/jsp/test.jsp").forward(req,resp);
}
// servlet api 转发
@RequestMapping("/add")
public String add2(HttpServletRequest req, HttpServletResponse resp){
    resp.sendRedirect("/index.jsp");
}
// springmvc 重定向
@RequestMapping("/add1")
public String add2(){
    return "redirect:/index.jsp";
}
// springmvc 转发
@RequestMapping("/add2")
public String add2(){
    return "/index.jsp";
}
// springmvc 转发
@RequestMapping("/add3")
public String add2(){
    return "forward:/index.jsp";
}

注意:重定向无法访问WEB-INF下的文件
注意:重定向无法携带原请求的参数,但是可以在指定重定向到哪个url前,在其中添加新参数,新参数会显示在重定向的url后面
注意:转发会携带原参数,但无法携带新数据(实测Spring的Model无法携带)

请求转发地址栏不会发生改变、只发送一次请求、能携带原有的参数,但只可以在同一个服务器中进行转发。

传统的重定向请求地址会改变(两次请求)、不能传递参数,但是利用SpringMVC的重定向可以携带和传递参数。重定向相比于请求转发可以跨服,但是不能直接重定向访问WEB-INF下的资源(可重定向后再进行一次请求转发)。

3.5 请求参数

url中参数名和controller的方法形参一致即可获取请求参数!

// 请求url为:/hello?name=pp&age=2&id=435
@RequestMapping("/hello")
public String a(String name,int age,String id){}

如果参数名称不一致,可以通过@RequestParam("xxx")显式映射url的参数

// 请求url为:/hello?username=pp&age=2&id=435
@RequestMapping("/hello")
public String a(@RequestParam("username")String name,int age,String id){}

可以将请求参数封装称一个实体,只要url请求参数能和实体中的属性名对应即可!没对应的为null

// 请求url为:/hello?name=pp&age=2&id=435
// User类中有name age id属性
@RequestMapping("/hello")
public String a(User user){}

3.6 返回结果

返回结果到前端有三种方式:
Model:只有几种方法用来存储数据(主要)
ModelMap:继承LinkedMap,还有自身的一些方法
ModelAndView:存储数据,可以设置跳转视图

4 乱码问题

实践中往往通过POST方式从网页上传递过来的数据有中文乱码问题,而GET方式没有这个问题,解决方法有两种,servlet过滤器,或者使用spring写好的过滤器

4.1 servlet过滤器

解决方式:

  1. 使用servlet过滤器进行过滤请求
    EncodingFilter.java
public class EncodingFilter implements Filter {
    @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);
    }
}
  1. 注册该过滤器
    web.xml
<filter>
    <filter-name>encodingfilter</filter-name>
    <filter-class>com.xiaopi3.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>encodingfilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注意:此时url为/*即拦截所有的请求,无论是路径还是文件,因为在返回视图时是一个jsp页面,同样需要捕获到该请求页面并转码,而/过滤该请求,只捕获动作,返回时的请求就不会被处理了,我们需要保证请求和响应的编码一致才行

4.2 spring过滤器

<filter>
    <filter-name>springencoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>springencoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

spring提供一个编码的过滤器,可以解决乱码问题,可能某些情况下对GET支持不好

4.3 其他方法

  1. 修改tomcat配置文件,设置编码格式:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

5 JSON(@RestController)

html中的script不能自闭合,必须成对出现

轻量级的数据传输格式,使用字符串表示,常用的包有:Jackson、fastjson、gson等

可以将对象转换成字符串,可以从字符串中恢复对象

注意:一般而言,Controller里返回的字符串会通过请求分发器去找视图解析器解析,但是如果想直接返回该字符串给前端的化,必须添加注解:@ResponseBody

注意:如果json中出现乱码,可以配置RequestMapping中的属性:

@RequestMapping(value="j",produces="application/json;charset=utf-8")
@ResponseBody
public String fun1(){}

由于在注解中配置方式,需要每个注解都配置,比较烦,可以在springmvc-servlet.xml中进行配置:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg name="defaultCharset" value="UTF-8"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

需要导入jackson包:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>

再次返回json字符串则显示正常:

@RestController
public class JsonController {
    @RequestMapping("/j1")
    public String fun1(){
        JSONObject json =new JSONObject();
        json.put("name","小皮3");
        json.put("age",19);
        return json.toString();
    }
}

6 SSM整合

环境:IDEA、MySQL5.7、Tomcat9、Maven3.6

  1. 导入依赖
    pom.xml
<dependencies>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.16</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>
</dependencies>

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
  1. 配置三个配置文件:spring核心配置文件,数据库properties,mybatis配置文件
    db.properties
# 注意,一定要写jdbc.driver而不是driver,要不然有可能会报错!!
jdbc.driver=com.mysql.jdbc.Driver
# 如果是mysql8+,需要添加时区:&serverTimezone=Asia/Shanghai
jdbc.url=jdbc:mysql://localhost:3306/ooo?useSSL=false&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456

mybatis-config.xml,其他交给spring去管理了

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.xiaopi3.pojo"/>
    </typeAliases>

</configuration>

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
">

    <import resource="classpath:spring-dao.xml"/>
    <import resource="classpath:spring-service.xml"/>
    <import resource="classpath:spring-mvc.xml"/>
    
</beans>

第一个:spring-dao配置
配置一下spring和数据库相关的配置
连接池:

  • dbcp:半自动化操作,不能自动连接
  • c3p0:自动化操作(自动加载配置文件,自动设置到对象中)
  • druid
  • hikari

spring-dao.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"
       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
">
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <property name="autoCommitOnClose" value="false"/>
        <property name="checkoutTimeout" value="10000"/>
        <property name="acquireRetryAttempts" value="2"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <property name="basePackage" value="com.xiaopi3.dao"/>
    </bean>

</beans>

配置文件分为几部分:
1 外部properties文件读取
2 c3p0连接池配置
3 sqlSessionFactory注入
4 使用Mapper扫描器对包进行扫描,并注入sqlSessionFactory,该类属于mybatis与spring整合的包

spring-service.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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">
    <context:component-scan base-package="com.xiaopi3.service"/>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

该配置文件分为两部分:
1 包扫描
2 配置spring事务管理器

spring-mvc.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
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
">
    <mvc:annotation-driven/>

    <mvc:default-servlet-handler/>

    <context:component-scan base-package="com.xiaopi3.controller"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

该配置文件分为4个部分:
1 注解驱动,mvc注入映射器和适配器
2 静态资源过滤
3 包扫描
4 视图解析器

  1. 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.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>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>
</web-app>

该配置文件主要做了两件事:
1 配置请求分发器,并注入spring总配置文件(因为时web项目,需要在这里读取总配置文件),设置spring即刻启动
2 配置启用spring编码过滤器

至此配置工作结束,开始业务工作!

对于POJO类可以采用lombok注释

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
    private int salary;
}

对于dao下的接口采用mybatis的方式:

public interface UserMapper {

    int addUser(User user);
    int deleteUserById(int id);
    int updateUser(User user);
    User findUser(int id);
    List<User> findAllUser();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopi3.dao.UserMapper">

    <insert id="addUser" parameterType="user">
        insert into `user` values(null,#{name},#{age},#{salary})
    </insert>

    <delete id="deleteUserById">
        delete from `user` where id=#{id}
    </delete>

    <update id="updateUser" parameterType="user">
        update `user` set name=#{name},age=#{age},salary=#{salary} where id=#{id}
    </update>

    <select id="findUser" resultType="user">
        select * from `user` where id=#{id}
    </select>

    <select id="findAllUser" resultType="user">
        select * from `user`
    </select>

</mapper>

对于控制层controller采用注解方式:

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/findAll")
    public String findAllUser(Model model){
        List<User> allUser = userService.findAllUser();
        model.addAttribute("users", JSON.toJSONString(allUser));
        return "users";
    }

    @RequestMapping("/find")
    public String find(int id,Model model){
        User user = userService.findUser(id);
        ArrayList<User> users = new ArrayList<>();
        users.add(user);
        model.addAttribute("users", JSON.toJSONString(users));
        return "users";
    }
}
  1. 启动tomcat,注意在tomcat的lib下导入需要的jar包,访问请求地址:/user/findAll,完毕

7 Ajax

掌握异步请求方式

<script>
function getValue(){
	$.post({
		url:"地址",
		data:{数据},
		success:function(data,status,xhr){}
	})
}
</script>

注意:回调函数中:data为返回值,status为:(“success”、“notmodified”、“error”、“timeout”、“parsererror”)中的一种,xhr为XMLHttpRequest对象
注意:post中可以不传递{}对象,直接传参:$.post(url,bodyData,function(responseData){})

动过标签获取input组件的value值:txt=$("input").val();
通过id获取某个组件:$("#id")
ajax入口函数:$(function(){入口}),写在入口中的表达式会依次执行
ajax设置组件css:$("#id").css("color":"green")

使用Ajax动态获取数据时建议后台使用@RestController来传递数据

@RestController
public class TestRestController {
    @RequestMapping("/doRest")
    public List<Map<String,Integer>> doRest(int num){
        List<Map<String, Integer>> maps = new ArrayList<>();

        for (int i = 0; i < num; i++) {
            Map<String, Integer> map = new HashMap<>();
            map.put("index",i);
            map.put("value",i*456/222);
            maps.add(map);
        }

        return maps;
    }
}

注意:如果报:org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type ...这种错误,表示没有找到json转换器,需要修改两个地方:

  1. 修改spring-mvc.xml,加上json转换器
<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg name="defaultCharset" value="UTF-8"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
  1. 添加jackson依赖
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>
  1. 在项目目录结构中将依赖jar包添到对应artifact的/WEB-INF/lib/下,重启tomcat即可!

8 拦截器

拦截器类似于servlet过滤器,与过滤器区别是:拦截器是AOP思想的应用

过滤器:任何java web工程都可以使用,配置了url-pattern为/*后可以进行资源过滤
拦截器:springmvc特有的,只拦截映射器中的请求,不拦截静态资源

定义拦截器:实现HandlerInterceptor接口

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("请求处理前");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("请求处理后");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求完成清理资源");
    }
}

注意:重写的三个方法中,最重要的是第一个方法,如果返回值为false则请求被拦截!否则放行。
在srping-mvc.xml中配置拦截器:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.xiaopi3.config.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

注意:path为/**指拦截/下所有请求以及子请求!!
启动tomcat请求任意controller映射,返回结果:

请求处理前
执行业务逻辑代码----------
请求处理后
请求完成清理资源

8.1 拦截器Demo:登录拦截

环境:SpringMVC环境

  1. 首先编写页面:主页:index.jsp、展示页:users.jsp、登录页:login.jsp
主页:
<a href="${pageContext.request.contextPath}/user/findAll">进入用户展示页面</a> 
<a href="${pageContext.request.contextPath}/goLogin">登录</a>

用户展示页:
<a href="${pageContext.request.contextPath}/logout">注销</a>
<h1>用户展示</h1>

登录页:
<form action="${pageContext.request.contextPath}/login" method="post">
    用户名:<input type="text" name="username"/>
    密码:<input type="password" name="password"/>
    <input type="submit" value="提交">
</form>
  1. 编写登录拦截器
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("请求处理前");
        String uri = request.getRequestURI();
        System.out.println(uri);
        if(uri.contains("login")||uri.contains("goLogin")){
            return true;
        }
        if("true".equals(request.getSession().getAttribute("login"))){
            return true;
        }
        response.sendRedirect("/goLogin");
        return false;
    }
}

注意:这里注意三点:1. 用户访问登陆页面不需要拦截;2. 用户登陆页面请求登录不需要拦截;3. 已经登录后不需要拦截

  1. 注册拦截器到spring-mvc.xml
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.xiaopi3.config.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

注意:可以在path中定义多级路径达到过滤部分路径不拦截的目的

  1. 编写controller
@Controller
public class LoginController {
    @RequestMapping("/goLogin")
    public String goLogin(){
        return "login";
    }
    @PostMapping("/login")
    public String login(HttpSession httpSession,String username,String password){
        if("xiaopi3".equals(username)&&"123456".equals(password)){
            httpSession.setAttribute("login","true");
            return "users";
        }
        return "login";
    }
    @RequestMapping("/logout")
    public String logout(HttpSession httpSession){
        httpSession.removeAttribute("login");
        return "redirect:/goLogin";
    }
}
  1. 启动tomcat测试效果:登录后可以进入内容展示页面,否则会跳转到登陆页面,注销后会跳转到登陆页面,并且需要登陆才能进入内容页。

9 文件上传

springmvc处理文件上传需要MultipartResolver

前端表单要求:为了能上传文件,必须将表单的method设置称POST,并将enctype设置为multipart/form-data,浏览器会以二进制流的方式来处理表单数据。apche发布的Commons FileUpload组件是Servlet/jsp最佳选择

  1. 导包
    注意:Springmvc将Commons FileUpload封装成了MultipartResolver,所以如果需要文件上传,下面两个包都需要
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
  1. 配置MultipartResolve
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--        must be same with jsp pageEncoding : default ISO-8859-1-->
    <property name="defaultEncoding" value="utf-8"/>
<!--        unit:Byte 10M=10*1024*1024Byte-->
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="4096"/>
</bean>

注意:该id要求必须为:multipartResolver

  1. 配置Controller
@Controller
public class UploadController {
    @RequestMapping("/upload")
    public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest httpServletRequest) throws IOException {
        // 获取文件名
        String uploadFileName = file.getOriginalFilename();

        // 如果文件名为空,则赋值默认:upload
        if("".equals(uploadFileName)){
            return "users";
        }
        System.out.println("上传文件名:"+uploadFileName);

        // 上传路径
        String _path = httpServletRequest.getSession().getServletContext().getRealPath("/upload");
        System.out.println(_path);

        File path = new File(_path);
        if(!path.exists()){
            path.mkdir();
        }
        File _file = new File(path,uploadFileName);
        if(_file.exists()){
            String[] split = uploadFileName.split("\\.");
            uploadFileName = split[0] + UUID.randomUUID()+"."+split[1];
            _file = new File(path,uploadFileName);
        }

        InputStream inputStream = file.getInputStream();
        FileOutputStream fileOutputStream = new FileOutputStream(_file);

        int len=0;
        byte[] array = new byte[1024];
        while((len=inputStream.read(array))!=-1){
            fileOutputStream.write(array,0,len);
        }
        inputStream.close();
        fileOutputStream.close();

        return "users";
    }
    @RequestMapping("/upload2")
    public String upload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest httpServletRequest) throws IOException {
        // 获取文件名
        String uploadFileName = file.getOriginalFilename();

        // 如果文件名为空,则赋值默认:upload
        if("".equals(uploadFileName)){
            return "users";
        }
        System.out.println("上传文件名:"+uploadFileName);

        // 上传路径
        String _path = httpServletRequest.getSession().getServletContext().getRealPath("/upload");
        System.out.println(_path);

        File path = new File(_path);
        if(!path.exists()){
            path.mkdir();
        }
        File _file = new File(path,uploadFileName);
        if(_file.exists()){
            String[] split = uploadFileName.split("\\.");
            uploadFileName = split[0] + UUID.randomUUID()+"."+split[1];
            _file = new File(path,uploadFileName);
        }

        // 通过CommonsMultipartFile方法直接写文件
        file.transferTo(_file);
        return "users";
    }
}

注意:两种方法的效果一样,不同之处在于IO流部分,第二种方式使用Springmvc包装好的方法transferTo进行文件写出。当没有选择文件之间点上传时,文件名为空,所以可以依此判断进行跳转。如果使用RestController可以使用ajax进行异步请求。

特别注意:参数输入部分:@RequestParam("file") CommonsMultipartFile file必须带上注解进行指定,否则报空指针异常!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值