1、概念
1.SpringMVC:接收浏览器的请求响应,对数据进行处理,然后返回页面进行显示
2.三层架构:分层分工,相互独立,协同工作的架构模式,
- m(模型层);v(视图层);c(控制层)
- dao持久化层(数据库);service业务层(逻辑运算);controller控制层(输入输出)
2、使用
1.导包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
<build>
<!--在build中配置resources来防止资源导出失败的问题-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2.web.xml新增配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--
需确保version="4.0"是最先的版本,不是则网上找下最新的。
先新建空项目,再添加框架支持Web,也可保证version是最新的
-->
<!-- 配置SpringMVC的核心控制器 -->
<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>
<!--springmvc.xml是springmvc的配置文件-->
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- servlet标签中的name与servlet-mapping标签中name的需一致 -->
<!-- /只匹配请求 /*jsp页面也匹配-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.新建springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解类 -->
<context:component-scan base-package="com.jiang.controller"/>
<!-- 让springmvc不处理静态资源 .css .js .html .mp3 .mp4等 -->
<mvc:default-servlet-handler/>
<!-- 使SpringMVC注解生效 :会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean,这是Spring MVC为@Controller分发请求所必需的-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property><!--jsp是我自己加的文件夹,没有时写/WEB-INF/就行-->
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
4、创建ControllerTest2
package com.jiang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("T1")
public class ControllerTest2 {
@RequestMapping("Test1")
public String Test1(Model model){
System.out.println("马上跳转");
model.addAttribute("msg","两小无猜终无情");//前台用${requestScope.msg}(可简写为${name})取值
return "test";//逻辑路径,test是在/WEB-INF/jsp/目录下,以.jsp结尾,所以/WEB-INF/jsp/test.jsp需写为test
/*
return "forward:login7";//请求转发(一般用于同一服务器,同一类里或不同类的跳转)
return "redirect:/login7";//重定向(主要用于跨服务器的跳转)
return "/index.jsp";//物理路径,也是转发过去的
*/
}
}
5、在jsp创建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
<br/>
<%-- 表单格式样例 --%>
<form method="get" action="login2">
用户:<input name="name" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
<form action="login3" method="post">
<h1>数组类型传递</h1>
抽烟<input type="checkbox" name="hobby" value="抽烟"><br/>
喝酒<input type="checkbox" name="hobby" value="喝酒"><br/>
烫头<input type="checkbox" name="hobby" value="烫头"><br/>
<input type="submit" value="提交"><br/>
</form>
<a href="login4?name=1111&password=222">超链接传值</a>
</body>
</html>
6、测试
访问:http://localhost:8080/项目名//T1/Test1 进行测试
3、resuful风格(http://localhost:8080/SSM/commit/root/123456)
1.好处:url更加简洁、传参数更加安全
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RestFulController {
//映射访问路径,前端通过【http://localhost:8080/SSM/commit/7/“我是password” 】这种进行访问
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable string p2, Model model,HttpSession session){
int result = p1+p2;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果:"+result);//前台用${requestScope.msg}(可简写为${name})取值
//session.setAttribute("name","小江");//前台用${sessionScope.name}取值
//返回视图位置
return "test";
}
//映射访问路径,必须是POST请求 value:url的值,method:提交方式 produces:指定响应体返回类型和编码
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String index2(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
}
2.提交方式
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
4、前端=传值=后端
@Controller
public class Usercontroller {
@RequestMapping("login")
//当前端为name,后端为username时用@RequestParam("name")String username来解决
public String login(@RequestParam("name")String username,String password) {
System.out.println("登录"+"用戶名:"+username+"密碼:"+password);//通过字段名传值,
return "NewFile.jsp";
}
@RequestMapping("login1")
public String login(User user) {
System.out.println(user);//通过对象传值,需保证User类中的字段名与前端的字段名一致,才能传值成功
return "NewFile.jsp";
}
@RequestMapping("login2")
public String login(String[] a) {
for (int i = 0; i < a.length; i++) {//通过数组传值,也需保证字段名称一致
System.out.println(a[i]);
}
return "NewFile.jsp";
}
@RequestMapping("login3")
public String login3(String name,String password) {
System.out.println("登录"+"用戶名:"+name+"密碼:"+password);
return "NewFile";
}
}
<form action="login1" method="post">
用户名:<input type="text" name="name" /><br />
密码:<input type="text" name="password" /><br />
<input type="submit" value="提交" />
</form>
***************************************
<form action="login2" method="post">
爱好:<input type="checkbox" name="a" value="跳高"/>跳高<br />
<input type="checkbox" name="a" value="休息"/>休息<br />
<input type="checkbox" name="a" value="看着办"/>看着办<br />
<input type="submit" value="提交" />
</form>
***************************************<br />
<a href="login3?name=江西&password=123">超链接</a>
5、后端=传值=前端(Model session)
从主页面进入login
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("login")
public String login3(Model m,HttpSession s) {
m.addAttribute("username", "江溪");
s.setAttribute("password", "123456");
return "NewFile";
}
<body>
新页面<br/>
${username}<br/>
${sessionScope.password}<br/>
</body>
6、传值时中文乱码处理
web.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>
<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>
7、JSON格式
1.js中JSON格式转换
<!--新建一个test.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
//编写一个javascript对象
var User={
name:"小江",
age:4,
sex:"男"
};
console.log(User);//F12-控制台查看打印信息
console.log("==========================================");
//将js对象 转换成 json对象,str={"name":"小江","age":4,"sex":"男"}
var str=JSON.stringify(User);
console.log(str);
console.log("==========================================");
//将json对象 转换成 js对象
var json=JSON.parse(str);
console.log(json);
</script>
</head>
<body>
</body>
</html>
2.jackson的使用
<!-- 1、导入jackson包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!-- 2、写pojo类 -->
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
3.web.xml中添加
<!--jackson处理返回给前端的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>
4.编写UserController,并进行测试
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.jiang.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestController//等同于@Controller+@ResponseBody
//指定响应体返回类型和编码可在springmvc-servlet.xml进行统一配置
//@RequestMapping(produces = "application/json;charset=utf-8")
public class UserControler {
@RequestMapping("Test11")
public String Test11() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("小江", 18, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
@RequestMapping("Test12")
public String Test12() throws JsonProcessingException {
//创建一个List,填充一些对象
List<User> list = new ArrayList<User>();
User user = new User("小江", 18, "男");
User user1 = new User("小江1", 18, "男");
User user2 = new User("小江2", 18, "男");
list.add(user);
list.add(user1);
list.add(user2);
//创建一个jackson的对象映射器,将我们的List解析成为json格式,直接返回
return new ObjectMapper().writeValueAsString(list);
}
@RequestMapping("Test13")
public String Test13() throws JsonProcessingException {
//创建一个List,填充一些对象
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定日期格式
mapper.setDateFormat(sdf);
//打印当前时间
System.out.println(new Date().toString());
//将我们的当前时间解析成为json格式,直接返回
return mapper.writeValueAsString(new Date());
}
}
3.fastjson2的使用
1.导包
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.20</version>
</dependency>
2.编写测试类
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.jiang.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestController//等同于@Controller+@ResponseBody
//指定响应体返回类型和编码可在springmvc-servlet.xml进行统一配置
//@RequestMapping(produces = "application/json;charset=utf-8")
public class UserControler {
@RequestMapping("Test14")
public String Test14() throws JsonProcessingException {
//创建一个List,填充一些对象
List<User> list = new ArrayList<User>();
User user = new User("小江", 18, "男");
User user1 = new User("小江1", 18, "男");
User user2 = new User("小江2", 18, "男");
list.add(user);
list.add(user1);
list.add(user2);
System.out.println("*******Java对象 转 JSON字符串*******");
System.out.println("JSON.toJSONString(list)==>"+JSON.toJSONString(list));//返回数据给前端时用
System.out.println("JSON.toJSONString(user1)==>"+JSON.toJSONString(user1));//返回数据给前端时用
System.out.println("\n****** JSON字符串 转 Java对象*******");
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.parseObject(str2,User.class)==>"+JSON.parseObject(str2,User.class));//处理前端数据时用
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.toJSONString());
System.out.println("\n****** JSON对象 转 Java对象 ******");
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+JSON.toJavaObject(jsonObject1, User.class));
return "ssss";
}
}
3.fastjson2的所有方法
// 把JSON文本parse转为JSONObject或者JSONArray
public static final Object parse(String text);
// 把JSON文本parse转成JSONObject
public static final JSONObject parseObject(String text);
// 把JSON文本parse转为JavaBean
public static final <T> T parseObject(String text, Class<T> clazz);
// 把JSON文本parse转成JSONArray
public static final JSONArray parseArray(String text);
//把JSON文本parse转成JavaBean集合
public static final <T> List<T> parseArray(String text, Class<T> clazz);
// 将JavaBean序列化为JSON文本
public static final String toJSONString(Object object);
// 将JavaBean序列化为带格式的JSON文本
public static final String toJSONString(Object object, boolean prettyFormat);
//将JavaBean转换为JSONObject或者JSONArray
public static final Object toJSON(Object javaObject);
8、拦截器(AOP思想的应用)
1.编写实现HandlerInterceptor接口的自定义拦截器
package com.jiang.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//做登录拦截时,可放行登录jsp。再判断用户是否登录,未登录跳转至登录页面,已登录放行
System.out.println("拦截前");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截后");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("清理");
}
}
2.配置文件applicationContext.xml中新增内容
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器,是手写的实现HandlerInterceptor接口的类,类里定义拦截的内容-->
<bean class="com.jiang.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3.编写MyTestController
访问http://localhost:8080/test测试
package com.jiang.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyTestController {
@RequestMapping("test")
public String test(){
System.out.println("我是test");
return "小江很OK";
}
}
9、文件上传下载
1.导包
<dependencies>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
2.配置文件applicationContext.xml中新增内容
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<!--上传文件的最大大小 -->
<property value="17367648787" name="maxUploadSize"/>
<!-- 上传文件的编码 -->
<property value="UTF-8" name="defaultEncoding"/>
</bean>
3.写jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2022/12/2/002
Time: 21:14
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/test">test</a>
<h1>文件上传</h1>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
<h1>文件下载</h1>
<a href="${pageContext.request.contextPath}/download">点击下载</a>
</body>
</html>
4.写FileController
package com.jiang.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@RestController
public class FileController {
@RequestMapping("test")
public String test(){
System.out.println("test");
return "test";
}
@RequestMapping("upload")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:" + realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath + "/" + file.getOriginalFilename()));
return "redirect:/index.jsp";
}
@RequestMapping("download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.webp";
//1、设置response 响应头
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);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}