目录
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次请求
结论:如果要保留请求域中的数据,使用转发,否则使用重定向。无论转发或重定向后续的代码都会执行。
- 新建空白Maven工程,并添加框架支持:JaveWeb
- 导入相关依赖
<!-- 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>
- 创建一个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); } }
- 创建对应页面
注意:如果需要保证用户不可见,需要放在WEB-INF下面<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
- 配置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
执行步骤:
- 浏览器发送请求给DispatcherServlet
- DispatcherServlet接收请求,给HandlerMapping去解析请求,寻找对应的HandlerExecution
- 找到HandlerExecution后,返回给DispatcherServlet,DispatcherServlet再去调用HandlerAdapter去执行该HandlerExecution,HandlerExecution中包装的就是Controller层的控制器类,执行过程中控制层会调用业务层,最终返回一个ModelAndView给HandlerAdapter
- HandlerAdapter拿到ModelAndView给DispatcherServlet,DispatcherServlet调用视图解析器ViewResolver,解析出数据和目标视图页面
- 跳转到终页面并插入数据
步骤:
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
步骤:
- 配置web.xml(基本不用变,每次写都直接copy即可),同上节一样
- 配置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>
- 新建控制器类:
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"; // 会被视图解析器处理,该字符串会作为视图名称
}
}
- 新建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过滤器
解决方式:
- 使用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);
}
}
- 注册该过滤器
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 其他方法
- 修改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
- 导入依赖
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>
- 配置三个配置文件: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 视图解析器
- 配置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";
}
}
- 启动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转换器,需要修改两个地方:
- 修改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>
- 添加jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
- 在项目目录结构中将依赖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环境
- 首先编写页面:主页: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>
- 编写登录拦截器
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. 已经登录后不需要拦截
- 注册拦截器到spring-mvc.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xiaopi3.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注意:可以在path中定义多级路径达到过滤部分路径不拦截的目的
- 编写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";
}
}
- 启动tomcat测试效果:登录后可以进入内容展示页面,否则会跳转到登陆页面,注销后会跳转到登陆页面,并且需要登陆才能进入内容页。
9 文件上传
springmvc处理文件上传需要MultipartResolver
前端表单要求:为了能上传文件,必须将表单的method设置称POST,并将enctype设置为multipart/form-data,浏览器会以二进制流的方式来处理表单数据。apche发布的Commons FileUpload组件是Servlet/jsp最佳选择
- 导包
注意: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>
- 配置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
- 配置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
必须带上注解进行指定,否则报空指针异常!!