SpringMVC学习笔记
SpringMVC
SpringMVC:
- controller:控制器
- 获得表单数据
- 调用业务逻辑
- 转向指定页面
- model:模型
- 业务逻辑
- 保存数据的状态
- view:视图
- 显示页面
SpringMVC优点:
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与 Spring 兼容性好,无缝集成
- 约定优于配置
- 功能强大:restful,数据验证,格式化等
- 将业务逻辑,数据,显示分离,降低各个模块之间的耦合,
初识SpringMVC
Spring的web框架围绕DispatcherServlet调度Servlet设计。
HelloSpringMVC项目搭建,pom.xml中导入spring-webmvc,servlet-api,jstl-api,jstl的jar包
web.xml
<!--注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- / 匹配所有的请求 (不包括.jsp)-->
<!-- /* 匹配所有的请求 (包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器,DispatcherServlet给它的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--Handler-->
<bean id="/hello" class="com.zr.controller.HelloController"/>
</beans>
HelloController
//注意:导入org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图
mv.setViewName("hello"); ///WEB-INF/jsp/hello.jsp
return mv;
}
}
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
注意:如果访问http://localhost:8080/hello出现404
选中自己的项目名,在WEB-INF下新建lib文件夹,点击+号,将项目的依赖添加到lib中,重启项目!!!
SpringMVC执行流程
- DispatcherServlet表示前置控制器,是整个SpringMVC控制的中心,用户发出请求,DispatcherServlet接收请求并拦截请求。
- HandlerMapping为处理器映射器,根据处理器请求url查找Handler,由DispatcherServlet调用。
- HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器。
- HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
- HandlerAdapter表示处理器适配器,按特定的规则执行Handler。
- Handler让具体的Controller执行。
- Controller将执行的信息返回给HandlerAdapter,如ModelAndView。
- HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
- DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
- 视图解析器将解析的逻辑视图名传给DispatcherServlet。
- 视图渲染呈现给用户。
使用注解开发SpringMVC
控制器Controller
-
控制器负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方式实现。
-
控制器负责解析用户的请求并将其转化为一个模型。
-
在SpringMVC中一个控制器类可以包含多个方法。
web.xml
<!-- 配置DispatcherServlet:这是SpringMVC的核心,请求分发器,前端控制器 -->
<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>
<!-- 启动级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--SpringMVC中:
/:匹配所有的请求。不匹配jsp页面
/*:匹配所有的请求。匹配jsp页面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动扫描包,让包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.zr.controller"/>
<!--让SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--支持注解驱动
在spring中使用@RequestMapping注解来完成映射关系,必须注册
DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter
这两个实例分别在类级别和方法级别处理
annotation-driven帮助我们完成上述两个实例的注入
-->
<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>
HelloController
@Controller
public class HelloController {
@RequestMapping("/h1")
public String hello(Model model){
//封装数据
model.addAttribute("msg","HelloSpringMVCAnnotation");
return "hello"; //视图解析器处理
}
}
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
RestFul风格
概念:RestFul就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
URL定义
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源
http://127.0.0.1/item/queryUser.action?id=1查询,GET
http://127.0.0.1/item/saveUser.action 新增,POST
http://127.0.0.1/item/updateUser.action 更新,POST
http://127.0.0.1/item/deleteUser.action?id=1 删除,GET或POST
使用RestFul操作资源:可以通过不同的请求实现不同的效果!
[http://127.0.0.1/item/zr 查询,GET
[http://127.0.0.1/item/ 新增,POST
[http://127.0.0.1/item/ 更新,PUT
[http://127.0.0.1/item/zr 删除,DELETE
学习测试
-
新建一个测试类RestFulController,在方法参数前面加@PathVariable注解,让方法参数的值对应绑定到一个URL模板变量上。
@Controller
public class RestFulController {
@RequestMapping("/add/{a}/{b}")
public String test(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果为"+res);
return "test"; //test.jsp
}
}
请求地址相同,得到结果不同的情况
//@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.DELETE)
//@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
public String test(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果1为"+res);
return "test";
}
@PostMapping("/add/{a}/{b}")
public String test2(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果2为"+res);
return "test";
}
web下a.jsp
<form action="/add/3/4" method="post">
<input type="submit">
</form>
web/WEB-INF/jsp/test.jsp
<body>
${msg}
</body>
重定向和转发
ModelAndView:根据view的名字,和视图解析器跳转到指定的页面。
使用springmvc来实现转发和重定向—–无视图解析器
@Controller
public class ModelTest1 {
@RequestMapping("/m1/t1")
public String test(Model model){
model.addAttribute("msg","ModelTest1");
// return "/WEB-INF/jsp/test.jsp";
//转发
// return "forward:/index.jsp";
//重定向
return "redirect:/index.jsp";
}
使用springmvc来实现转发和重定向—–有视图解析器
@Controller
public class HelloController {
@RequestMapping("/h1")
public String hello(Model model){
//封装数据
model.addAttribute("msg","HelloSpringMVCAnnotation");
return "hello"; //视图解析器处理
}
}
数据处理
User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
UserController类,使用@RequestParam(“***”)接收参数
@Controller
@RequestMapping("/user")
public class UserController {
//localhost:8080/user/t1?name=***
@RequestMapping("/t1")
public String test1(@RequestParam("name") String name, Model model){
//接收前端参数
System.out.println("接收到前端的参数为"+name);
//将结果传递给前端
model.addAttribute("msg",name);
//跳转视图
return "test";
}
/*
1.接收用户传递的参数,判断参数的名字,假设名字直接在方法上,就可以直接用
2.假设传递的是一个对象User,匹配User对象的字段名
*/
//http://localhost:8080/user/t2?id=1&name=zzzrrr&age=20
//前端接受的是一个对象:id,name,age
@RequestMapping("/t2")
public String test2(User user){
System.out.println(user);
return "test";
}
乱码处理
在开发中,我们会经常遇到乱码问题,在Servlet阶段使用的是编写过滤器过滤。现在SpringMVC也给我们提供了一个过滤器,在xml中配置,然后重启服务器。
web下form.jsp
<body>
<form action="/e/t1" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
EncodingController
@Controller
public class EncodingController {
@PostMapping("/e/t1")
public String test1(String name, Model model){
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
}
编码过滤器
<!--配置SpringMVC的乱码过滤-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
JSON
什么是JSON:
- JSON(JavaScript Object Notation,js对象标记)是一种轻量级数据交换格式
- 采用完全独立于编程语言的文本格式来存储和表示数据
- 易于人阅读和编写,同时也易于机器解析和生成,并有效提升网络传输速率
- 对象表示为键值对,数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
// 编写一个javascript对象
var user = {
name:"周周",
age:"20",
sex:"南"
};
// 将js对象转化为json对象
var json = JSON.stringify(user);
console.log(json);
// json转化为javascript对象
var js = JSON.parse(json);
console.log(js)
console.log(user);
</script>
</head>
<body>
</body>
</html>
Jackson的使用
Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 是最流行的 json 解析器之一 。
Jackson 最常用的 API 就是基于”对象绑定” 的 ObjectMapper。
使用前pom.xml加入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>xml
<version>2.10.0</version>
</dependency>
web.xml
<!-- 配置DispatcherServlet:这是SpringMVC的核心,请求分发器,前端控制器 -->
<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>
<!-- 启动级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--SpringMVC中:
/:匹配所有的请求。不匹配jsp页面
/*:匹配所有的请求。匹配jsp页面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置SpringMVC的乱码过滤-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动扫描包,让包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.zr.controller"/>
<!--解决json乱码-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
User类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
UserController
@RestController //不会走视图解析器,
public class UserController {
//注解解决json乱码 建议在xml中解决乱码
// @RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
@RequestMapping("/j1")
//@ResponseBody //不会走视图解析器,会直接返回一个字符串
public String json1() throws JsonProcessingException {
//jackson ObjectMapper
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("周周",20,"南");
String s = mapper.writeValueAsString(user);
return s;
}
}
返回一个json数组,返回格式化时间(方法加在UserController类中)
@RequestMapping("/j2")
public String json2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<User> list = new ArrayList<User>();
User user1 = new User("周周1",20,"南");
User user2 = new User("周周2",20,"南");
User user3 = new User("周周3",20,"南");
User user4 = new User("周周4",20,"南");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
String s = mapper.writeValueAsString(list);
return s;
}
@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//自定义日期的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
//return mapper.writeValueAsString(date);
return mapper.writeValueAsString(sdf.format(date));
}
@RequestMapping("/j4")
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//使用ObjectMapper 格式化输出
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sdf);
Date date = new Date();
return mapper.writeValueAsString(date);
}
封装思想
工具类
public class JsonUtil {
public static String getMapper(Object object,String dateFormat){
ObjectMapper mapper = new ObjectMapper();
//使用ObjectMapper 格式化输出
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
public static String getMapper(Object object){
return getMapper(object,"yyyy-MM-dd HH:mm:ss");
}
}
测试工具类(方法加在UserController类中)
@RequestMapping("/j5")
public String json5() {
Date date = new Date();
return JsonUtil.getMapper(date,"yyyy-MM-dd HH:mm:ss");
}
@RequestMapping("/j6")
public String json6() {
List<User> list = new ArrayList<User>();
User user1 = new User("周周1",20,"南");
User user2 = new User("周周2",20,"南");
User user3 = new User("周周3",20,"南");
User user4 = new User("周周4",20,"南");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return JsonUtil.getMapper(list);
}
FastJson
FastJson是阿里巴巴开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象de转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。
导包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
FastJson三个主要的类
- JSONObject 代表json对象,JSONObject实现了Map接口
- JSONArray 代表json数组对象,内部是由list接口中的方法完成操作
- JSON代表 JSONObject 和 JSONArray的转化
@RequestMapping("/j7")
public String json7() {
List<User> list = new ArrayList<User>();
User user1 = new User("周周1",20,"南");
User user2 = new User("周周2",20,"南");
User user3 = new User("周周3",20,"南");
User user4 = new User("周周4",20,"南");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//java对象转json字符串
String s = JSON.toJSONString(list);
System.out.println(s);
String s1 = JSON.toJSONString(user1);
System.out.println("s1: "+s1);
//json字符串转java对象
User s2 = JSON.parseObject(s1,User.class);
System.out.println("s2: "+s2.toString());
//java对象转json对象
JSONObject s3 = (JSONObject) JSON.toJSON(user2);
System.out.println("s3: "+s3.toJSONString());
// json对象转java对象
User s4 = JSON.toJavaObject(s3, User.class);
System.out.println("s4: "+s4);
return "hello";
}
}
整合SSM
新建maven一个项目ssmbuild
环境配置:
pom.xml中导入以下依赖和允许静态资源导出
<!--导入依赖 junit,数据库驱动,连接池,Servlet,jsp,mybatis,mybatis-spring,spring,lembok,spring-jdbc,jstl,standard等-->
<dependencies>
......
</dependencies>
<!--静态资源导出-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
database.properties
jdbc.driver=com.mysql.jdbc.Driver
#如果使用的是MySQL 8.0+,增加一个时区的配置
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=false&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
mybatis-config.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>
<!-- 配置数据源,交给spring去做-->
<typeAliases>
<package name="com.zr.pojo"/>
</typeAliases>
<mappers>
<mapper class="com.zr.dao.BookMapper"/>
</mappers>
</configuration>
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:database.properties"/>
<!--连接池
dbcp:手动化操作,不能自动连接
c3p0:自动化操作,可以自动化加载配置文件,并且可以自动设置到对象中
durid
hikari
-->
<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}"/>
<!--c3p0私有属性-->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!--关闭连接后不自动commit-->
<property name="autoCommitOnClose" value="false"/>
<!--连接超时时间-->
<property name="checkoutTimeout" value="10000"/>
<!--连接失败,自动重连次数-->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--配置dao接口扫描包,动态的实现了dao接口注入到spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--要扫描的dao包-->
<property name="basePackage" value="com.zr.dao"/>
</bean>
</beans>
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: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">
<!-- 扫描service下的包-->
<context:component-scan base-package="com.zr.service"/>
<!--将所有的业务类注入到spring,可以通过注解或者配置实现-->
<bean id="BookServiceImpl" class="com.zr.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!--声明式事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
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"/>
</beans>
BookMapper.xml
<?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.zr.dao.BookMapper">
<insert id="addBook" parameterType="Books">
insert into books (bookName,bookCounts,detail)
values (#{bookName},#{bookCounts},#{detail});
</insert>
<delete id="deleteBookById" parameterType="int">
delete from books where bookID=#{id};
</delete>
<update id="updateBook" parameterType="Books">
update books set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail}
where bookID=#{bookID};
</update>
<select id="selectBookById" resultType="Books">
select * from books where bookID=#{id};
</select>
<select id="selectAllBook" resultType="Books">
select * from books;
</select>
</mapper>
web.xml 【classpath:applicationContext.xml】bean的创建交给了applicationContext.xml
<!--DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--乱码过滤-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--session-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {
private int bookID;
private String bookName;
private int bookCounts;
private String detail;
}
BookMapper
public interface BookMapper {
//增加一本书
int addBook(Books books);
//删除一本书
int deleteBookById(@Param("id") int id);
//修改一本书
int updateBook(Books books);
//查询一本书
Books selectBookById(@Param("id") int id);
//查询全部
List<Books> selectAllBook();
}
BookService
public interface BookService {
//增加一本书
int addBook(Books books);
//删除一本书
int deleteBookById(@Param("id") int id);
//修改一本书
int updateBook(Books books);
//查询一本书
Books selectBookById(@Param("id") int id);
//查询全部
List<Books> selectAllBook();
}
BookServiceImpl
public class BookServiceImpl implements BookService{
//service调用dao层:组合dao层
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
public int addBook(Books books) {
return bookMapper.addBook(books);
}
public int deleteBookById(int id) {
return bookMapper.deleteBookById(id);
}
public int updateBook(Books books) {
return bookMapper.updateBook(books);
}
public Books selectBookById(int id) {
return bookMapper.selectBookById(id);
}
public List<Books> selectAllBook() {
return bookMapper.selectAllBook();
}
}
Ajax
Ajax:异步,能在无需加载整个页面的情况下,更新部分网页的技术。
Ajax不是一种编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。
web.xml配置DispatcherServlet和encoding,spring-mvc.xml配置视图解析器,扫描包,支持注解驱动,静态资源支持
开启窗口
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe测试体验页面无刷新</title>
<script>
function go() {
var url = document.getElementById("url").value;
document.getElementById("iframe1").src=url;
}
</script>
</head>
<body>
<div>
<p>请输入地址:</p>
<p>
<input type="text" id="url" value="https://www.cnblogs.com/zhou-zr/">
<input type="button" value="提交" onclick="go()">
</p>
</div>
<div>
<iframe id="iframe1" style="width: 100%;height: 500px">
</iframe>
</div>
</body>
</html>
Ajax的核心就是XMLHttpRequest。
Ajax异步加载数据
package com.zr.pojo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;java
private String name;
private String sex;
}
AjaxController
package com.zr.controller;
@RestController
public class AjaxController {
@RequestMapping("/t1")
public String test(){
return "hello";
}
@RequestMapping("/a")
public void a1(String name, HttpServletResponse response) throws IOException {
System.err.println("name--->>"+name);
if ("zr".equals(name)){
response.getWriter().println("true");
}else {
response.getWriter().println("false");
}
}
}
index.jsp
<head>
<title>$Title$</title>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<%-- <script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.js"></script>--%>
<script>
function a(){
$.ajax({
url:"${pageContext.request.contextPath}/a",
data:{"name":$("#username").val()},
success:function (data) {
alert(data);
}
})
}
</script>
</head>
<body>
<%-- 失去焦点的时候,发送一个请求到后台--%>
用户名:<input type="text" id="username" onblur="a()">
</body>
test2.jsp
<html>
<head>
<title>Title</title>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
console.log("111");
$.post("${pageContext.request.contextPath}/a2",function (data) {
// console.log(data);
var html="";
for (let i = 0; i < data.length; i++) {
html += "<tr>"+
"<td>"+ data[i].id+"</td>"+
"<td>"+ data[i].name+"</td>"+
"<td>"+ data[i].sex+"</td>"+
"</tr>"
}
$("#context").html(html)
});
})
});
</script>
</head>
<body>
<input type="button" value="加载数据" id="btn">
<table>
<tr>
<td>编号</td>
<td>姓名</td>
<td>性别</td>
</tr>
<tbody id="context">
<%-- 数据--%>
</tbody>
</table>
</body>
</html>
AjaxController
@RequestMapping("/a2")
public List<User> a2(){
List<User> userList = new ArrayList<User>();
//添加数据
userList.add(new User(1,"周zrr","南"));
userList.add(new User(2,"周","南"));
userList.add(new User(3,"周周周","南"));
return userList;
}
Ajax验证用户名
login.jsp
<html>
<head>
<title>Title</title>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<%-- <script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.js"></script>--%>
<script>
function a1() {
$.ajax({
url:"${pageContext.request.contextPath}/a3",
data: {"name":$("#name").val()},
success:function (data) {
// alert(data);
// console.log(data);
if (data.toString()==='ok'){
$("#userinfo").css("color","green");
}else {
$("#userinfo").css("color","red");
}
$("#userinfo").html(data);
}
})
}
function a2() {
$.ajax({
url:"${pageContext.request.contextPath}/a3",
data:{"pwd":$("#pwd").val()},
success:function (data) {
//alert(data);
// console.log(data);
if (data.toString()==='ok'){
$("#pwdinfo").css("color","green");
}else {
$("#pwdinfo").css("color","red");
}
$("#pwdinfo").html(data);
}
})
}
</script>
</head>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()">
<span id="userinfo"></span>
</p>
<p>
密码:<input type="password" id="pwd" onblur="a2()">
<span id="pwdinfo"></span>
</p>
</body>
</html>
AjaxController
@RequestMapping("/a3")
public String a3(String name,String pwd){
String msg="";
if (name!=null){
//这些数据应该从数据库中查
if ("admin".equals(name)){
msg = "ok";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("123456".equals(pwd)){
msg = "ok";
}else {
msg = "密码有误";
}
}
return msg;
}
拦截器
SpringMVC中的拦截器类似于Servlet中的过滤器filter,用于对处理器进行预处理和后处理,开发者可以定义拦截器来实现特定的功能。
过滤器和拦截器的区别:拦截器是Aop思想的具体应用。
过滤器
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置/*后,可以对所有要请求的资源进行拦截
拦截器
- 拦截器是SpringMVC框架自己的,只有使用了该框架才可以使用
- 拦截器只会拦截访问控制器的方法,访问静态资源不会拦截
搭建环境测试
application.xml
<!--自动扫描包,让包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.zr.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
web.xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web下index.jsp
<body>
<h1>
<a href="${pageContext.request.contextPath}/user/gologin">登录界面</a></h1>
<h1> <a href="${pageContext.request.contextPath}/user/main">首页</a></h1>
</body>
WEB-INF/jsp/login.jsp
<body>
<form action="${pageContext.request.contextPath}/user/login" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
WEB-INF/jsp/main.jsp
<body>
<%--在WEB_INF下的所有界面,只能通过servlet或controller访问--%>
<h1>首页</h1>
${username}
${pageContext.request.getSession("userinfo").getValue(username)}
<p>
<a href="${pageContext.request.contextPath}/user/goOut">注销</a>
</p>
</body>
LoginController
package com.zr.controller;
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/main")
public String main(){
return "main";
}
@RequestMapping("/gologin")
public String login(){
return "login";
}
@RequestMapping("/login")
public String login(String username, String password, HttpSession session, Model model){
//把用户的信息存在Session中
session.setAttribute("userInfo",username);
model.addAttribute("username",username);
System.out.println(model.getAttribute("username"));
return "main";
}
@RequestMapping("/goOut")
public String goOut(HttpSession session){
//把用户的信息删除
session.removeAttribute("userinfo");
return "main";
}
}
配置拦截器LoginIntercepter
public class LoginIntercepter implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("登录拦截器==========");
HttpSession session = request.getSession();
//放行的判断
//登录页面要放行 包含login 即gologin和login
if (request.getRequestURI().contains("login")){
return true;
}
if (session.getAttribute("userinfo")!=null){
return true;
}
//判断什么情况下没有登录
System.out.println("返回登录页==========");
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
}
配置到application.xml中
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--包括这个请求下的所有请求-->
<mvc:mapping path="/user/**"/>
<bean class="com.zr.config.LoginIntercepter"/>
</mvc:interceptor>
</mvc:interceptors>
文件上传
SpringMVC中配置CommonsMultipartResolver。
前端表单method设置为post,并将enctype设置为multipart/form-data。
对表单中enctype属性的详细说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的value属性值,采用这种编码方式的表单会将表单域中的值处理成URL编码方式。
- multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的的内容也封装到请求参数中,不会对字符编码。
- text/plain:除了把空格转化为 “+” 号外,其它字母都不做编码处理,这种方式适用直接通过表单发送文件。
在以上项目的pom文件中新增commons-fileupload,commons-io。
index.jsp
<body>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit" value="upload">
</form>
</body>
application.xml中增加文件上传配置
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--请求的编码格式,必须和jsp的pageEncoding的属性一致,以便正确读取表单内容,默认ISO-8859-1-->
<property name="defaultEncoding" value="utf-8"/>
<!--上传文件大小限制,单位是字节,10485760=10M-->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
controller
package com.zr.controller;
@RestController
public class FileController {
//@RequestParam("file"),将name=file属性的文件封装成CommonsMultipartResolver对象
//批量上传CommonsMultipartFile
@RequestMapping("/upload")
public String Fileupload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//获取文件名
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传的文件名为:"+uploadFileName);
//上传路径保存设置
String path = request.getSession().getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址为:"+realPath);
InputStream is = file.getInputStream();
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName));
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}
上传方式二
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径设置
String path = request.getSession().getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址为:"+realPath);
//通过 的方法直接写文件(注意)
file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));
return "redirect:/index.jsp";
}
下载文件
@RequestMapping("/downLoad")
public String downLoad(HttpServletResponse response,HttpServletRequest request) throws IOException {
//要下载的图片地址
String path = request.getSession().getServletContext().getRealPath("/upload");
String fileName = "1.jpg";
//设置respons响应头
response.reset();//设置在页面不缓存,清空buffer
response.setCharacterEncoding("utf-8");//字符编码
response.setContentType("multipart/form-data");//二进制创数数据
//设置响应头
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path, fileName);
InputStream in = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
//
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
out.flush();
}
out.close();
in.close();
return null;
}