SpringMVC
基本概念
MVC设计模型
M model模型 JavaBean
V View视图 JSP
C Controller控制器 Servlet
SpringMVC是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级Web框架
它通过一套注解, 让一个简单的Java类成为处理请求的控制器, 而无需实现任何接口(HttpServlet)
同时它还支持RESTful变成风格的请求
SpringMVC的优势
- 清晰的角色划分
前端控制器 DispatcherServlet
请求到处理器映射 HandlerMapping
处理器适配器 HandlerAdapter
视图解析器 ViewResolver
验证器 Validator
命令对象 Command 请求参数绑定到的对象叫命令对象
表单对象 Form Object 提供给表单展示和提交到的对象叫表单对象
入门案例
新建maven webapp项目
file -> new -> module -> maven -> create from archetype -> maven archetype webapp -> 填写groupId, ArtifactId -> 完成
解决maven项目创建过慢
properties加入
Name: archetypeCatalog
Value: internal
pom文件依赖
<!-- 版本锁定 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<!-- 添加到properties标签内-->
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
环境搭建
建立以上几个目录和文件
resources -> new -> XML Configuration File -> Spring Config -> springmvc.xml
配置web.xml
配置dispacherServlet
配置init-param, 导入springmvc.xml
web.xml
:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispacherServlet: 控制作用, 指挥心-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 设置第一次创建时就创建此页面-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置可加载静态资源文件, 方法2-->
<!--配置默认Servlet-->
<!-- <servlet>-->
<!-- <servlet-name>default</servlet-name>-->
<!-- <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>-->
<!-- </servlet>-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 配置该Servlet的url地址, / 表示任何url地址都会到达该Servlet-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 静态资源文件的后缀名-->
<!-- <servlet-mapping>-->
<!-- <servlet-name>default</servlet-name>-->
<!-- <url-pattern>*.js</url-pattern>-->
<!-- </servlet-mapping>-->
<!-- <servlet-mapping>-->
<!-- <servlet-name>default</servlet-name>-->
<!-- <url-pattern>*.png</url-pattern>-->
<!-- </servlet-mapping>-->
</web-app>
配置springmvc.xml
开启注解扫描
配置视图解析器对象
开启SpringMVC框架的支持
注意/WEB-INF/pages/
一定不要忘了最前面的 /
springmvc.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 开启SpringMVC框架的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置开启静态资源访问, 静态资源放在webapp/static目录下-->
<!-- <mvc:resources mapping="/static/**" location="/static/"></mvc:resources>-->
</beans>
java目录下新建cn.itcast.controller.HelloController类
类上配置@Controller注解
方法上配置@RequestMapping(path="/hello")注解, 返回success字符串
表示访问 主目录/hello 则会跳转到该方法(相当于servlet上配置 `@WebServlet"/hello")`)
该方法转发至success.jsp页面(相当于页面内转发`request.getRequestDispatcher("index.jsp").forward(request, response)`)
HelloController.java
:
package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器
@Controller
public class HelloController {
//请求映射
@RequestMapping(path = "/hello")
public String sayHello() {
System.out.println("Hello SpringMVC");
return "success";//返回的字符串默认表示返回jsp页面的名字
}
}
编写index.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<%--写相对路径--%>
<a href="hello">入门程序</a>
</body>
</html>
编写success.jsp文件
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
整个目录结构如下:
配置tomcat:
启动tomcat后浏览器自动访问index.jsp文件
点击其中的超链接, 跳转至DispatcherServlet
解析/hello路径, 跳转至HelloController类下的sayHello方法
sayHello()方法返回"success"字符串, 转发至DispatcherServlet
DispatcherServlet转发至视图解析器对象, internalResourceViewResolver
internalResourceViewResolver解析""success"字符串, 跳转至success.jsp页面, 返回给浏览器
浏览器内部跳转至success.jsp页面
流程说明
- 启动服务器, 加载一些配置文件, load-on-startup标签配置
1.1. DispatcherServlet对象创建
1.2. springmvc.xml被加载
1.3. 开启注解扫描, HelloController对象创建
1.4. 配置视图解析器
springmvc.xml
1.5. 配置支持注解扫描<!-- 视图解析器对象--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
<!-- 开启SpringMVC框架的支持--> <mvc:annotation-driven></mvc:annotation-driven>
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
入门案例中涉及的组件
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c
dispatcherServlet 是整个流程控制的中心
由它调用其它组件处理用户的请求
dispatcherServlet 的存在降低了组件之间的耦合性
HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器
SpringMVC 提供了不同的映射器实现不同的映射方式
例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
它就是我们开发中要编写的具体业务控制器
由 DispatcherServlet 把用户请求转发到 Handler
由Handler 对具体的用户请求进行处理
HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver:视图解析器
View Resolver 负责将处理结果生成 View 视图
View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址
再生成 View 视图对象
最后对 View 进行渲染将处理结果通过页面展示给用户
View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括: jstlView、 freemarkerView、 pdfView等。
我们最常用的视图就是 jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
mvc:annotation-driven说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用<mvc:annotation-driven>
自 动 加 载 RequestMappingHandlerMapping ( 处 理器 映 射 器 ) 和RequestMappingHandlerAdapter ( 处 理 器适 配 器 )
可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>
替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept
ionResolver"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"
></bean>
<!-- End -->
注意:
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还有具体的使用场景)。
RequestMapping注解
-
RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
-
RequestMapping注解可以作用在方法和类上
- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- @RequestMapping(path = “/testRequestMapping”)也可以简写成@RequestMapping("/testRequestMapping")
-
RequestMapping的属性
- path 指定请求路径的url
- value value属性和path属性是一样的, 只有value属性时可以省略
- mthod 指定该方法的请求方式
- params 指定限制请求参数的条件, 请求必须包含该参数, 可以写params= {“name”}或者params= {“name=value”}, 如果请求不包含参数(params= {“name”})或者参数值不一样(params= {“name=value”}), 则请求不能到达
- headers 发送的请求中必须包含的请求头
params实例:
控制器的代码:
/**
* 删除账户
* @return
*/
@RequestMapping(value="/removeAccount",params= {"accountName","money>100"})
public String removeAccount() {
System.out.println("删除了账户");
return "success";
}
jsp 中的代码:
<!-- 请求参数的示例 -->
<a href="account/removeAccount?accountName=aaa&money>100">删除账户,金额 100</a>
<br/>
<a href="account/removeAccount?accountName=aaa&money>150">删除账户,金额 150</a>
注意:
当我们点击第一个超链接时,可以访问成功。
当我们点击第二个超链接时,无法访问。
请求参数的绑定
1. 简单参数绑定
form表单:
<a href="param/testParam?username=hehe">请求参数绑定</a>
controller类:
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/testParam")
public String testParam(String username) {
System.out.println("执行了...");
System.out.println("username=" + username);
return "success";
}
}
提交form表单, 则controller类会自动接收到username属性, 并打印
2. 把数据封装到java对象中
在提交表单时, 设置表单项的name属性为getXxx方法中的xxx, Controller类传入响应类型的对象, 即可封装
Account类:
public class Account implements Serializable {
private String username;
private String password;
private Double money;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money=" + money +
'}';
}
}
form表单:
<form action="param/saveAccount" method="post">
姓名: <input type="text" name="username"><br>
密码: <input type="text" name="password"><br>
金额: <input type="text" name="money"><br>
<input type="submit" value="提交">
</form>
controller类:
@Controller
@RequestMapping("/param")
public class ParamController {
//请求参数绑定把数据封装到javabean的类中
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
System.out.println("执行了...");
System.out.println(account);
return "success";
}
}
可将表单中的数据封装到java类对象中
3. 将引用类型的数据封装到java对象中
name="引用对象.属性"
的写法可将引用类型的数据封装
例如 Account对象的User user, 表单设置name="user.uname"
, 即可封装user对象的uname属性
User类:
public class User implements Serializable {
private String uname;
private Integer age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", age=" + age +
'}';
}
}
Account类:
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private User user;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money=" + money +
", user=" + user +
'}';
}
}
form表单:
<form action="param/saveAccount" method="post">
姓名: <input type="text" name="username"><br>
密码: <input type="text" name="password"><br>
金额: <input type="text" name="money"><br>
用户姓名: <input type="text" name="user.uname"><br>
用户年龄: <input type="text" name="user.age"><br>
<input type="submit" value="提交">
</form>
4. 数据封装到List和Map集合中
class Account
List list
Map map
name="list[0].uname"
name="map['one'].age"
Account类:
package cn.itcast.domain;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public class Account implements Serializable {
private String username;
private String password;
private Double money;
// private User user;
private List<User> list;
private Map<String , User> map;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money=" + money +
", list=" + list +
", map=" + map +
'}';
}
}
form表单:
<%-- 把数据封装到Account类中, 类中存在list和map的集合--%>
<form action="param/saveAccount" method="post">
姓名: <input type="text" name="username"><br>
密码: <input type="text" name="password"><br>
金额: <input type="text" name="money"><br>
用户姓名: <input type="text" name="list[0].uname"><br>
用户年龄: <input type="text" name="list[0].age"><br>
用户姓名: <input type="text" name="map['one'].uname"><br>
用户年龄: <input type="text" name="map['one'].age"><br>
<input type="submit" value="提交">
</form>
解决中文乱码
在web.xml文件的<web-app>
标签内<servlet>
标签上面配置<filter>
一定要写在<servlet>
标签上面, 否则xml文件报错
<!-- 解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
自定义类型转换器
- 表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。
- 如果想自定义数据类型转换,可以实现Converter的接口
自定义类型转换器:
package cn.itcast.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 把字符串转换成日期的转换器
*/
public class StringToDateConverter implements Converter<String, Date>{
/**
* 进行类型转换的方法
*/
public Date convert(String source) {
// 判断
if(source == null) {
throw new RuntimeException("参数不能为空");
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// 解析字符串
Date date = df.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("类型转换错误");
}
}
}
注册自定义类型转换器,在springmvc.xml配置文件中编写配置, 在<beans>
标签中添加如下内容:
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!-- 开启SpringMVC框架的支持-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
在form表单中提交 yyyy-MM-dd 类型的数据即可转换成Date类型的数据
获取Servlet原生API
只需在方法中传入相关参数即可
Controller类:
@RequestMapping("/param")
public class ParamController {
//获取原生API
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("执行了...");
System.out.println(request);
HttpSession session = request.getSession();
System.out.println(session);
ServletContext servletContext = session.getServletContext();
System.out.println(servletContext);
return "success";
}
}
html页面:
<a href="param/testServlet">Servlet原生API</a>
相关注解
@RequestParam
- 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
- 属性
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认值是true,必须提供
Controller类:
@Controller
@RequestMapping("/anno")
public class AnnoController {
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name = "name")String username) {
//表示获取表单传入的name属性, 并赋值给 String username
System.out.println("执行了...");
System.out.println(username);
return "success";
}
}
jsp页面:
<a href="anno/testRequestParam?name=哈哈">RequestParam</a>
@RequestBody
- 作用: 用于获取请求体内容。 直接使用得到是 key=value&key=value…结构的数据。
get 请求方式不适用。 - 属性: required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false, get 请求得到是 null。
Controller类:
@Controller
@RequestMapping("/anno")
public class AnnoController {
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body) {
System.out.println("执行了...");
System.out.println(body);
return "success";
}
}
form表单:
<form action="anno/testRequestBody" method="post">
用户姓名: <input type="text" name="uname"><br>
用户年龄: <input type="text" name="age"><br>
用户生日: <input type="text" name="date"><br>
<input type="submit" value="提交">
</form>
@ModelAttribute
- 作用:该注解是 SpringMVC4.3 版本以后新加入的。
它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。 - 属性:
value:用于获取数据的 key。 key 可以是 POJO 的属性名称,也可以是 map 结构的 key。 - 应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。
在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题.
实例:
有返回值的方法:
Controller类:
@Controller
@RequestMapping("/anno")
public class AnnoController {
//modelAttribute注解
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
@ModelAttribute
public User showUser(String uname) {
System.out.println("showUser执行了...");
//模拟通过uname查询数据库, 并返回User对象
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
return user;
}
}
form表单:
<form action="anno/testModelAttribute" method="post">
用户姓名: <input type="text" name="uname"><br>
用户年龄: <input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
执行过程:
showUser()先执行, 根据uname(模拟)查询数据库得到user对象, 将属性封装到user中, 并返回user对象
testModelAttribute()执行, 获取user对象并输出
无返回值的方法
传入Map集合, 在传入User对象的参数上加注解:
public String testModelAttribute(@ModelAttribute("user1") User user)
Controller类:
@Controller
@RequestMapping("/anno")
public class AnnoController {
//modelAttribute注解
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("user1") User user) {
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
// @ModelAttribute
// public User showUser(String uname) {
// System.out.println("showUser执行了...");
// //模拟通过uname查询数据库, 并返回User对象
// User user = new User();
// user.setUname(uname);
// user.setAge(20);
// user.setDate(new Date());
// return user;
// }
@ModelAttribute
public void showUser(String uname, Map<String, User> map) {
System.out.println("showUser执行了...");
//模拟通过uname查询数据库, 并返回User对象
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
map.put("user1", user);
}
}
响应
响应之返回值是String
Controller类
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testString")
public String testString() {
System.out.println("testString方法执行了");
User user = new User();
user.setUsername("妹妹");
user.setPassword("123");
user.setAge(30);
model.addAttribute("user", user);
return "success";
return "success";
}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>入门成功</h3>
${user.username}
${user.password}
</body>
</html>
将跳转到success.jsp页面
显示结果:
入门成功
妹妹 123
响应之返回值为void
默认跳转至@RequestMapping(“path”)中设置的地址
可通过转发/ 重定向/ getWriter()返回内容 跳转或返回
Controller类:
@Controller
@RequestMapping("/user")
public class UserController {
//返回值类型为void
@RequestMapping("/testVoid")
//默认跳转至user/testVoid.jsp路径
public void testVoid1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("testVoid方法执行了");
//编写请求转发
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, (ServletResponse) response);
//重定向
// response.sendRedirect(request.getContextPath()+"/WEB-INF/pages/success.jsp");
//设置utf-8编码, 解决中文乱码
// response.setCharacterEncoding("UTF-8");
// response.setContentType("text/html;charset=UTF-8");
// //直接进行响应
// response.getWriter().write("你好");
return;
}
}
返回值为ModelAndView
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了");
User user = new User();
user.setUsername("美美");
user.setPassword("123");
user.setAge(23);
mv.addObject("user", user);
mv.setViewName("success");
//将转发至success.jsp页面
return mv;
}
}
使用关键字进行转发或重定向
//使用关键字的方式进行转发或者重定向
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect() {
System.out.println("testForwardOrRedirect方法执行了");
//转发
// return "forward:/WEB-INF/pages/success.jsp";
//重定向, 不用加项目名称 request.getContextPath(), 框架会自动添加
return "redirect:/index.jsp";
}
常用注解
参考链接:
https://blog.csdn.net/chengqiuming/article/details/81675528
https://blog.csdn.net/yaheng100/article/details/81741693
@RequestBody 接收json数据
@ResponseBody 响应json数据
springmvc开启静态资源访问
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。
方法1:
解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->`html
设置以上路径中的静态资源不再拦截
设置之后rebuild project, tomcat restart server
方法2:
如果配置正确,路径也正确但是无法访问静态资源,可尝试以下办法:
- 保持上述配置不变
- maven的pom中导入catalina包依赖
- 修改web.xml配置文件:
<!--配置默认Servlet-->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<!--如果需要加载png, css等文件, 可以配置相应的 *.png, *.css等等 -->
参考文章:https://blog.csdn.net/qq_42110985/article/details/107107266
注意事项
- servlet-mapping标签要写在servlet标签之后, 顺序为servlet, servlet-mapping, 否则xml文件会报错
即:
<servlet>servlet1</servlet>
<servlet>servlet2</servlet>
<servlet-mapping>mapping1<servlet-mapping>
<servlet-mapping>mapping2<servlet-mapping>
- 由于浏览器缓存问题, 已经加载过的静态资源, 即使重新修改配置(删掉上述配置), 删除IDEA中的资源文件(删除js, png等文件), ctrl+shift+delet清除浏览器缓存, 也仍然可以加载. (自己电脑上亲身实验得出, 不同环境可能有差异)
- 注意在修改配置后要rebuild project, 重启tomcat服务, 否则仍然可能出现不能加载静态资源文件的问题
- 在向jsp页面中引入新的静态资源文件(图片, js文件等)之后, 也需要rebuild和重启tomcat服务, 否则仍然可能出现无法加载静态资源文件的问题
- 也可以把静态资源文件同意放在一个文件夹下, 按方法1配置resources路径
<mvc:resources location="/static/" mapping="/static/**"/>
<!-- 把静态资源放在static下的js, css, img文件夹下-->
案例: ResponseBody响应json数据
以入门案例为基础
导入maven依赖:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>catalina</artifactId>
<version>6.0.29</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>response</title>
<script type="text/css" src="static/css/css1.css"></script>
<script type="text/javascript" src="static/js/jquery-3.5.1.js"></script>
</head>
<body>
<script>
$(function () {
$("#btn").click(function () {
alert("btn");
$.ajax({
//编写json格式, 设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"hehe", "password":"123", "age":"20"}',
dataType:"json",
type:"post",
success:function (data) {
//data: 服务器端响应的json数据, 进行解析
alert(data.username);
alert(data.password);
alert(data.age);
}
});
});
});
</script>
<input type="button" id="btn" value="发送ajax的请求">
</body>
</html>
User类:
提供username, password, age字段和响应的getter和setter方法
Controller类:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user) {
System.out.println("testAjax方法执行了");
//客户端发送ajax的请求, 穿的是json字符串, 后端把json字符串封装到user对象中
System.out.println(user);
//做响应
//模拟查询数据库
user.setUsername("hehe");
user.setAge(40);
//做响应
return user;
}
}
文件上传
传统方式文件上传
文件上传的必要前提
form 表单的 enctype 取值必须是: multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型
method 属性取值必须是 Post
提供一个文件选择域<input type=”file” />
实现:
导入maven依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
jsp页面form表单:
<form action="user/upload" method="post" enctype="multipart/form-data">
<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
Controller类:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/upload")
public String fileupload(HttpServletRequest request) throws Exception {
System.out.println("fileupload执行了");
//使用fileupload组件完成文件上传
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断该路径是否存在
File file = new File(path);
if (! file.exists()) {
//创建文件夹
file.mkdirs();
}
//解析request对象, 获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历
for (FileItem item: items
) {
//进行判断, 当前item对象是否是上传文件项
if (item.isFormField()) {
//说明是普通表单项
}else {
//说明是上传文件项
//获取上传文件的名称
String filename = item.getName();
//把文件名称设置成唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "_" + filename;
//完成文件上传
item.write(new File(path, filename));
//删除临时文件
item.delete();
}
}
return "upload_success";
}
}
上传文件会出现在target文件夹下, 文件主目录下的uploads文件夹中, 上传后浏览器页面跳转至upload_success.jsp
SpringMVC传统方式实现文件上传
传统方式的文件上传, 指的是我们上传的文件和访问的应用存在于同一台服务器上。
并且上传完成之后,浏览器可能跳转。
实现:
导入maven依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
springmvc.xml配置文件解析器对象
<!-- 配置文件解析器对象-->
<!-- id 的值是固定的-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
</bean>
form表单:
<h3>springmvc文件上传</h3>
<form action="user/upload2" method="post" enctype="multipart/form-data">
<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
Controller类:
@Controller
@RequestMapping("/user")
public class UserController {
//springmvc方式文件上传
@RequestMapping("/upload2")
//MultipartFile upload 必须和表单form中的name属性的值一样
public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("springmvc上传");
//使用fileupload组件完成文件上传
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断该路径是否存在
File file = new File(path);
if (! file.exists()) {
//创建文件夹
file.mkdirs();
}
//获取上传文件的名称
String filename = upload.getOriginalFilename();
//把文件名称设置成唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + filename;
//完成文件上传
upload.transferTo(new File(path, filename));
return "upload_success";
}
}
SpringMVC跨服务器方式实现文件上传
分服务器的目的:
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
实现:
新建一个tomcat的图片服务器项目 fileuploadserver
file -> new -> module maven -> web-app -> fileuploadserver
添加新的tomcat服务器, 修改HTTP port 和JMX port, 将fileuploadserver项目部署到tomcat服务器fileupload
注意此处tomcat服务器URL: http://localhost:9090/fileuploadserver/, 后面Controller中要与此一致
在fileuploadserver项目target/fileuploadserver目录下新建uploads文件夹
启动tomcat服务器
导入maven依赖:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
jsp文件的form表单:
<h3>springmvc跨服务器文件上传</h3>
<form action="user/upload3" method="post" enctype="multipart/form-data">
<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
Controller类:
@Controller
@RequestMapping("/user")
public class UserController {
//springmvc跨服务器方式文件上传
@RequestMapping("/upload3")
//MultipartFile upload 必须和表单form中的name属性的值一样
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("springmvc跨服务器文件上传");
//定义上传文件服务器路径
String path = "http://localhost:9090/fileuploadserver/uploads/";
//获取上传文件的名称
String filename = upload.getOriginalFilename();
//把文件名称设置成唯一值
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + filename;
//创建客户端的对象
Client client = Client.create();
//和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
//上传文件
webResource.put(upload.getBytes());
return "upload_success";
}
}
细节:Tomcat默认不能进行delete和put,需要修改 readonly 属性;
https://blog.csdn.net/qq_40181435/article/details/105684221
SpringMVC异常处理
异常处理思路
Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理
实现步骤
自定义异常类 SysException:
package cn.itcast.exception;
public class SysException extends Exception {
private String message;
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public SysException(String message) {
this.message = message;
}
}
自定义异常处理器SysExceptionResolver:
package cn.itcast.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* Try to resolve the given exception that got thrown during handler execution,
* returning a {@link ModelAndView} that represents a specific error page if appropriate.
* <p>The returned {@code ModelAndView} may be {@linkplain ModelAndView#isEmpty() empty}
* to indicate that the exception has been resolved successfully but that no view
* should be rendered, for instance by setting a status code.
*
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler, or {@code null} if none chosen at the
* time of the exception (for example, if multipart resolution failed)
* @param ex the exception that got thrown during handler execution
* @return a corresponding {@code ModelAndView} to forward to, or {@code null}
* for default processing
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
SysException e = null;
if (ex instanceof SysException) {
e = (SysException)ex;
} else {
e = new SysException("系统正在维护...");
}
//创建ModelAdnView对象
ModelAndView mv = new ModelAndView();
mv.addObject("erroMsg", e.getMessage());
mv.setViewName("error");
return mv;
}
}
配置异常处理器
springmvc.xml中加入以下配置
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"></bean>
springmvc.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 开启SpringMVC框架的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置开启静态资源访问, 静态资源放在webapp/static目录下-->
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"></bean>
</beans>
Controller:
@Controller
@RequestMapping("/user")
public class UserController3 {
@RequestMapping("/testException")
public String testException() throws Exception{
System.out.println("testExcetion执行了");
//模拟异常
try {
int a = 10 / 0;
} catch (Exception e) {
e.printStackTrace();
throw new SysException("查询所有用户出现错误了...");
}
return "success";
}
}
jsp页面:
<h3>异常处理</h3>
<a href="user/testException">异常信息</a>
将跳转至WEB-INF/pages/erro.jsp页面
error.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>erropage</h3>
${erroMsg}
</body>
</html>
跳转后显示内容:
erropage
查询所有用户出现错误了...
SpringMVC中的拦截器
拦截器的概述
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口。
实现步骤
创建类,实现HandlerInterceptor接口,重写需要的方法
Myinterceptor1:
//自定义拦截器
public class Myinterceptor1 implements HandlerInterceptor {
/**
* 预处理, controller方法执行前
* return true 放行, 执行下一个拦截器, 如果没有, 执行controller中的方法
* return false 不放行,
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...前");
//设置页面跳转
//request.getRequestDispatcher("/WEB-INF/pages/erro.jsp").forward(request, response);
// return false;
return true;
}
//后处理, controller方法执行后, success.jsp执行之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后");
//设置页面跳转
//request.getRequestDispatcher("/WEB-INF/pages/erro.jsp").forward(request, response);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后");
//不能再跳转到其他页面
}
}
在springmvc.xml中配置拦截器类
<mvc:interceptors>
<mvc:interceptor>
<!-- 要拦截的方法-->
<mvc:mapping path="/user/**"/>
<!-- 不要拦截的方法-->
<!-- <mvc:exclude-mapping path="/"/>-->
<!-- 配置拦截器对象-->
<bean class="cn.itcast.interceptor.Myinterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
jsp页面, index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h3>执行成功</h3>
<% System.out.println("success.jsp执行了...");%>
</body>
</html>
点击jsp页面中的超链接, 跳转至WEB-INF/pages/success.jsp
控制台输出结果:
MyInterceptor1执行了...前
MyInterceptor1执行了...后
success.jsp执行了...
MyInterceptor1执行了...最后
HandlerInterceptor接口中的方法
- preHandle方法是controller方法执行前拦截的方法
可以使用request或者response跳转到指定的页面
return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
return false不放行,不会执行controller中的方法。 - postHandle是controller方法执行后执行的方法,在JSP视图执行前。
可以使用request或者response跳转到指定的页面
如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。 - postHandle方法是在JSP执行后执行
request或者response不能再跳转页面了
配置多个拦截器
执行顺序:
MyInterceptor1执行了...前
MyInterceptor1执行了...前2
MyInterceptor1执行了...后2
MyInterceptor1执行了...后
success.jsp执行了...
MyInterceptor1执行了...最后2
MyInterceptor1执行了...最后
SSM整合
搭建开发环境
mysql版本: Server version: 8.0.20 MySQL Community Server - GPL
mysql中创建数据表
create database ssm;
create table account(
id int primary key auto_increment,
name varchar(100),
money double(7,2),
);
创建maven webapp moudel
pom文件引入依赖
注意mysql-connector版本与mysql的兼容问题, 高版本mysql需要高版本mysql-connector 8.0.20
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>8.0.20</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies><!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version><scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
创建controller, service, dao, domain文件夹和相应文件
Account.java
package cn.itcast.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
AccountDao.java
package cn.itcast.dao;
import cn.itcast.domain.Account;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import java.util.LinkedList;
import java.util.List;
public interface AccountDao {
//查询所有账户
@Select("select * from account")
public List<Account> findAll();
//保存账户信息
@Insert("insert into account(name, money) values(#{name}, #{money})")
public void saveAccount(Account account);
}
AccountService.java
package cn.itcast.service;
import cn.itcast.domain.Account;
import java.util.List;
public interface AccountService {
//查询所有账户
public List<Account> findAll();
//保存账户信息
public void saveAccount(Account account);
}
AccountServiceImpl.java
package cn.itcast.service.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("业务层: 查询所有账户...");
//return accountDao.findAll();
return null;
}
@Override
public void saveAccount(Account account) {
System.out.println("业务层: 保存账户...");
//accountDao.saveAccount(account);
}
}
AccountController.java
package cn.itcast.controller;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(Model model) {
System.out.println("表现层: 查询所有账户...");
//调用service的方法
//List<Account> list = accountService.findAll();
//model.addAttribute("list", list);
return "list";
}
@RequestMapping("/save")
public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//accountService.saveAccount(account);
//response.sendRedirect(request.getContextPath()+"/account/findAll");
return;
}
}
log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=info, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
搭建Spring框架
配置controller注解不扫描(交给springmvc扫描)
applicationContext.xml
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启注解的扫描, 希望处理service和dao, controller不需要Spring框架去处理-->
<context:component-scan base-package="cn.itcast">
<!-- 配置哪些注解不扫描-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- Spring整合MyBatis框架-->
<!-- 配置连接池-->
<!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">-->
<!-- <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>-->
<!-- <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"></property>-->
<!-- <property name="user" value="root"></property>-->
<!-- <property name="password" value=""></property>-->
<!-- </bean>-->
<!-- 配置SqlSessionFactory工厂-->
<!-- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">-->
<!-- <property name="dataSource" ref="dataSource"></property>-->
<!-- </bean>-->
<!-- 配置AccountDao接口所在包-->
<!-- <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">-->
<!-- <property name="basePackage" value="cn.itcast.dao"></property>-->
<!-- </bean>-->
<!-- 配置Spring框架声明式事务管理-->
<!-- 配置事务管理器-->
<!-- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">-->
<!-- <property name="dataSource" ref="dataSource"></property>-->
<!-- </bean>-->
<!-- 配置事务通知-->
<!-- <tx:advice id="txAdvice" transaction-manager="transactionManager">-->
<!-- <tx:attributes>-->
<!-- <tx:method name="find*" read-only="true"/>-->
<!-- <tx:method name="*" isolation="DEFAULT"></tx:method>-->
<!-- </tx:attributes>-->
<!-- </tx:advice>-->
<!-- 配置AOP增强-->
<!-- <aop:config>-->
<!-- <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service.impl.*ServiceImpl.*(..))"></aop:advisor>-->
<!-- </aop:config>-->
</beans>
测试Spring
TestSpring.java
import cn.itcast.service.AccountService;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void run1() {
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
AccountService as = (AccountService) ac.getBean("accountService");
as.findAll();
}
}
如果能正常输出, 进行下一步
搭建SpringMVC框架
web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 设置配置文件的路径-->
<!-- <context-param>-->
<!-- <param-name>contextConfigLocation</param-name>-->
<!-- <param-value>classpath:applicationContext.xml</param-value>-->
<!-- </context-param>-->
<!-- 解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置Spring的监听器, 默认只加载WEB-INF目录下的applicationContext.xml配置文件, 需要设置配置文件的路径-->
<!-- <listener>-->
<!-- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
<!-- </listener>-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描, 只扫描Controller注解-->
<context:component-scan base-package="cn.itcast">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 过滤静态资源-->
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<!-- 开启SpringMVC注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<a href="account/findAll">测试查找</a>
<h3>测试包</h3>
<form action="account/save" method="post">
姓名: <input type="text" name="name">
金额: <input type="text" name="money">
<input type="submit" value="保存">
</form>
</body>
</html>
经AccountController的findAll方法返回跳转至list.jsp页面
list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>list页面</h3>
${list}
<h3>JSTL</h3>
<c:forEach items="${list}" var="account">
${account.name}+${account.money}<br>
</c:forEach>
</body>
</html>
tomcat部署项目, 测试springmvc, 如果能正常访问跳转至list.jsp则成功
搭建Mybatis框架
SqlMapConfig.xml
<?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>
<!-- 配置环境-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///ssm?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 引入映射配置文件-->
<mappers>
<!-- 两种方式, 写类名或者包名, 包名则包括包下的所有类-->
<!-- <mapper class="cn.itcast.dao.AccountDao"></mapper>-->
<package name="cn.itcast.dao"/>
</mappers>
</configuration>
TestMybatis.java
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestMybatis {
@Test
public void run1() throws IOException {
//加载配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession对象
SqlSession session = factory.openSession();
//获取到代理对象
AccountDao dao = session.getMapper(AccountDao.class);
//查询所有数据
List<Account> accounts = dao.findAll();
System.out.println(accounts);
//关闭资源
session.close();
in.close();
}
@Test
public void run2() throws IOException {
//加载配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession对象
SqlSession session = factory.openSession();
//获取到代理对象
AccountDao dao = session.getMapper(AccountDao.class);
Account account = new Account();
account.setName("熊三");
account.setMoney(34d);
dao.saveAccount(account);
//提交事务
session.commit();
//查询所有数据
List<Account> accounts = dao.findAll();
System.out.println(accounts);
//关闭资源
session.close();
in.close();
}
}
如果能正常输出, 则配置成功
Spring整合Mybatis
Spring 接管 MyBatis 的 Session 工厂
配置自动扫描所有 Mapper 接口和文件
配置 spring 的事务
在applicationContext.xml beans目录下加入以下配置(见之前的xml文件中被注释的部分)
application.xml
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启注解的扫描, 希望处理service和dao, controller不需要Spring框架去处理-->
<context:component-scan base-package="cn.itcast">
<!-- 配置哪些注解不扫描-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- Spring整合MyBatis框架-->
<!-- 配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"></property>
<property name="user" value="root"></property>
<property name="password" value=""></property>
</bean>
<!-- 配置SqlSessionFactory工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置自动扫描所有 Mapper 接口和文件, AccountDao接口所在包-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"></property>
</bean>
<!-- 配置Spring框架声明式事务管理-->
<!-- 配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" isolation="DEFAULT"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 配置AOP增强-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service.impl.*ServiceImpl.*(..))"></aop:advisor>
</aop:config>
</beans>
在AccountService中调用AccounDao的方法
AccountServiceImpl.java
package cn.itcast.service.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("业务层: 查询所有账户...");
return accountDao.findAll();
}
@Override
public void saveAccount(Account account) {
System.out.println("业务层: 保存账户...");
accountDao.saveAccount(account);
}
}
运行SpringTest中的run1()方法, 如果能成功查询到数据, 则整合成功
SpringMVC整合Spring
配置Spring的监听器
web.xml中加入以下内容
<!-- 配置Spring的监听器, 默认只加载WEB-INF目录下的applicationContext.xml配置文件, 需要设置配置文件的路径-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
手动指定配置文件的路径
<!-- 设置配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
web.xml
加入后web.xml如下:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 设置配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置Spring的监听器, 默认只加载WEB-INF目录下的applicationContext.xml配置文件, 需要设置配置文件的路径-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
启动tomcat服务器, 访问index.jsp中的超链接, 跳转至list.jsp, 查询到ssm.account表中的数据
改写controller, service, dao
在controller, service, dao下的各java类中调用响应的方法
AccountController.java
package cn.itcast.controller;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(Model model) {
System.out.println("表现层: 查询所有账户...");
//调用service的方法
List<Account> list = accountService.findAll();
model.addAttribute("list", list);
return "list";
}
@RequestMapping("/save")
public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
accountService.saveAccount(account);
response.sendRedirect(request.getContextPath()+"/account/findAll");
return;
}
}
AccountServiceImpl.java
package cn.itcast.service.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("业务层: 查询所有账户...");
return accountDao.findAll();
}
@Override
public void saveAccount(Account account) {
System.out.println("业务层: 保存账户...");
accountDao.saveAccount(account);
}
}
AccountDao.java
dao方法不变
index.jsp:
<%--
Created by IntelliJ IDEA.
User: Michael
Date: 2020/7/31
Time: 23:27
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<a href="account/findAll">测试查找</a>
<h3>测试包</h3>
<form action="account/save" method="post">
姓名: <input type="text" name="name">
金额: <input type="text" name="money">
<input type="submit" value="保存">
</form>
</body>
</html>
启动tomcat, 出现如下页面
输入数据, 点击保存, 跳转至list.jsp页面
完成.