这里是javaWeb工程
1.Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springMVC-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!--自定义标签中写上spring的版本,下面可以用${srping-version}来引用}-->
<spring-version>5.3.16</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</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-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<!--spring-mvc的JSON转换工具依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
</dependencies>
</project>
2.创建SpringMVC配置文件
在resources下创建spring-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:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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="xin.students"/>
<!--开启注Aspect生成代理对象-->
<aop:aspectj-autoproxy/>
<!--开启mvc注解配置-->
<mvc:annotation-driven/>
</beans>
3.在web.xml中配置SpringMVC的前端控制器
SpringMVC气功了一个名为DispatcherServlet的类[SpringMVC前端控制器],用于拦截用户请求交由SpringMVC处理。
<?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">
<!--服务器启动时就会实例化springMVC的前端控制器,同时会加载spring的配置文件-->
<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:spring-servlet.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>
</web-app>
SpringMVC的使用
在SpringMVC中,我们不用Servlet,而是把交给接收用户和请求处理用户请求的类:Controlelr(控制器)。
创建控制器
1.创建一个名为xin.students.controllercs的包(包需要在Spring注解扫描的范围内)。
2.在xin.students.controllercs包下创建一个类(这个类什么也不需要继承和实现),这里创建的是
BookController类。
3.在BookController类上添加@Controller注解声明此类为SpringMVC的控制器。
4.在BookController类上添加@RequestMapping("/book")声明此控制器的请求路径,斜杠可以有也可以没有,@RequestMapping("url")中的参数是url,类似于@WebServlet("/url")的作用。
package xin.students.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/book")
public class BookController {
}
在控制器类中定义处理请求的方法
在一个控制器类中可以定义多个方法处理不同的请求。
在每个方法上添加@RequestMapping("/url")用于声明当前方法请求的url。
如果类上面不加RequestMapping("/book"),则访问时直接用方法上面的url。
package xin.students.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add") //方法访问路径location/book/add
public void add(){}
@RequestMapping("/list") //方法访问路径location/book/list
public void list(){}
}
前端提交数据到控制器
创建前端页面
在webapp下创建book-add.jsp,表单的action属性设置控制器类的url和队形方法的url的组合。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h3>添加图书</h3>
<form action="/book/add" method="post">
<p>图书名称:<input type="text" name="name"/></p>
<p>图书作者:<input type="text" name="author"/></p>
<p>图书价格:<input type="text" name="price"/></p>
<p>图书名称:<input type="submit" value="提交"/></p>
</form>
</body>
</html>
静态资源配置
静态资源:就是项目中的HTML,CSS,JS,图片,字体等。
静态资源放行配置
在springMVC配置文件,添加如下资源放行的配置,放行css文件夹下所有静态资源文件[webapp文件夹为根目录]。
<mvc:resources mapping="/css/**" location="/css/"/>
拦截器<url-pattern>/</url-pattern>中"/*"和"/"的区别
"/*" 拦截所有的http请求,包括.jsp的请求,都会作为控制器类的请求路径类处理。
"/" 拦截所有的HTTP请求,但不包括.jsp的请求[jsp中引用的css文件等,也会被拦截],但是不会放 行静态资源请求(http/css/js/图片)。
前端页面提交数据
http传参的三种方式:请求头,请求行,请求体。
请求行传值:表单提交,URL提交,$.ajax请求的url传值,$.post()和$.get()中的传值。
请求头传值:ajax封装请求头数据。
$.ajax({
...
headers:{}
...
})
请求体传值:ajax封装请求体数据
$.ajax({
...
data:{}
...
})
1、表单提交[请求行传值]:输入框余姚提供name属性springMVC控制器是通过name属性取值的。
2、URL提交[请求行传值]:<a href="book/add?bookName=java">。
3、AJAX提交:请求行,请求头,请求体都可以传值。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h3>添加图书</h3>
<form action="/book/add" method="post">
<p>图书名称:<input type="text" name="name"/></p>
<p>图书作者:<input type="text" name="author"/></p>
<p>图书价格:<input type="text" name="price"/></p>
<p>图书名称:<input type="submit" value="提交"/></p>
</form>
<h3>超链接提交</h3>
<a href="${pageContext.request.contextPath}/book/add?name=java"></a>
<h3>超链接提交</h3>
<input type="button" value="ajax提交" id="btn1">
<script type="text/javascript" src="js/jquery-3.6.0.js"></script>
<script type="text/javascript">
$(function () {
$("#btn1").click(function () {
let obj = {};
obj.bookName = "java";
obj.bookAothor = "张三";
obj.bookPrice = 3.33;
$.ajax({
url: "book/add",
type: "post",
headers: {};
contentType: "application/json", //因为下面传的是对象,所以这里声明一下传json
data: obj;
success: function (result) {
console.log(result);
}
})
});
});
</script>
</body>
</html>
接收请求行传递的参数
@RequestParma注解用于接收请求行提交的数据,参数的name属性,必须写在方法的参数前。
如果方法参数前加了@RequestParma注解,前端传过来的数据中就必须要有对应name的数据。
否则会报下面的错误
org.springframework.web.servlet.DispatcherServlet.noHandlerFoundNo
mapping for POST /book/book/add
org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logExceptionResolv
ed [org.springframework.web.bind.MissingServletRequestParameterException:
Required request parameter '没有对应上的@RequestParam("xxx")中xxx的名称' for method
parameter type String is not present]
注:前端传过来几个值,方法就写几个参数,然后把@RequestParma("name")写在参数前去获取前端请求行传递过来的值,如果方法参数的名称与请求行中的name属性一直,可以不写@RequestParma("name")【只有请求行参数与传过来的name名称相同,参数前才可以不写注解】,什么注解都不写的话,方法的参数默认接收请求行的数据。
前端使用请求行的方式提交数据
<form action="/book/add" method="post">
<p>图书名称:<input type="text" name="name"/></p>
<p>图书作者:<input type="text" name="author"/></p>
<p>图书价格:<input type="text" name="price"/></p>
<p>图书名称:<input type="submit" value="提交"/></p>
</form>
控制器接收请求行数据
如果前端发过来的数据与方法参数中的名称不一样,需要写@RequestParam("name")来指定对应参数
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add") //方法访问路径location/book/add
public void add(@RequestParam("name") String n,
@RequestParam("author") String a,
@RequestParam("price") Double p) {
System.out.println("book---add");
System.out.println(n + " " + a + " " + p);
}
}
控制器接收请求行数据
如果前端发过来的数据与方法参数中的名称一样,可以不写@RequestMapping("name")来指定对应参数
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add") //方法访问路径location/book/add
public void add(String name, String author, Double price) {
System.out.println("book---add");
System.out.println(name + " " + author + " " + price);
}
@RequestMapping("/list") //方法访问路径location/book/list
public void list() {
System.out.println("book---list");
}
}
如果前端提交的是表单,表单中的key与类中的属性一样,可以用类直接接收。
<form action="/test/addBook" method="post">
<p>图书名称:<input type="text" name="name"/></p>
<p>图书作者:<input type="text" name="author"/></p>
<p>图书价格:<input type="text" name="price"/></p>
<p>图书时间:<input type="text" name="date"/></p>
<p>图书名称:<input type="submit" value="提交"/></p>
</form>
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/addBook")
public String addBook(Book book){
return "tips.jsp";
}
}
接收请求头传递的参数
@RequestHeader("key")用于接收请求头提交的数据,必须写在参数前。
@接收请求头数据时RequestHeader("key")必须要写。
前端使用请求头的方式传递数据
$("#btn1").click(function () {
$.ajax({
url: "book/list",
type: "post",
headers: {
xin: "heihei"
}
})
});
控制器接收请求头数据
@Controller
@RequestMapping("/book")
public class BookController {
//接收请求头的数据,只能接收ajax的请求头数据
@RequestMapping("/list") //方法访问路径location/book/list
public void list(@ @RequestHeader("xin") String xin) {
System.out.println("book---list");
System.out.println(xin);
}
}
接收请求体传递的参数
@RequestBody把前端传过来的JSON转为对象,该注解必须写在方法参数前。
@RequestBody只能接收前端对象转成JSON后的数据,这个注解依赖于jackson包。
使用请求体的方式传递参数,该参数必须是对象的JSON格式
let obj = {};
obj.name = "java";
obj.author = "张三";
obj.price = 3.33;
$.ajax({
url: "book/update",
type: "post",
contentType: "application/json", //因为下面传的是对象,所以这里声明一下传json
//spring-mvc接收请求体数据时必须是对象的JSON格式[contentType必须设置为"application/json"],
data: JSON.stringify(obj), //JSON.stringify(xxxobj)把xxx对象转为JSON格式
success: function (result) {
console.log(result);
}
})
接收前端请求体中的数据,前端传过来的数据必须是对应的JSON格式
@Controller
@RequestMapping("/book")
public class BookController {
//接收请求体的数据
@RequestMapping("/update")
public void update(@RequestBody Book book) {
System.out.println(book);
}
}
Book类的代码
public class Book {
private String name;
private String author;
private Double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
控制器相应前端请求
控制器响应同步请求
同步请求::form,超链接。
注:同步请求一般会跳转到其它页面。
处理同步请求的方法的返回类型定义为String或ModelAndView,以实现页面的跳转。
方法返回类型类为String
转发:浏览器的URL为接口地址,如:localhost/book/add。
重定向:浏览器的URL为跳转到的地址,如:"localhost/tips.jsp"。
返回值为String,返回路径为[如:"/tips.jsp"]为转发。
返回值为String,返回路径为[如:"redirect:/book/add"]为重定向。
返回值为String时:处理完请求后让前端自动跳转到函数返回值写的路径。
例如:这里处理完请求后让前端跳转到“/tips.jsp“页面。
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add")
public String add(@RequestParam("name") String name,
@RequestParam("author") String author,
@RequestParam("price") Double price) {
System.out.println("book---add");
System.out.println(name + " " + author + " " + price);
//return "redirect:/tips.jsp"为重定向
return "/tips.jsp"; //这里为转发
}
}
方法返回类型类为ModelAndView
返回值为ModelAndView,构造参数为[如:"/tips.jsp"]为转发。
返回值为ModelAndView,构造参数为[如:"redirect:/tips.jsp"]为重定向。
返回值为:ModelAndView与String功能一样,都是让前端跳转到指定页面。
返回值为ModelAndView时:处理完请求后让前端自动跳转到函数返回值写的路径。
例如:这里处理完请求后让前端跳转到“/tips.jsp“页面。
浏览器的地址为:http://localhost/book/add
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add")
public ModelAndView add(@RequestParam("name") String name,
@RequestParam("author") String author,
@RequestParam("price") Double price) {
System.out.println("book---add");
System.out.println(name + " " + author + " " + price);
//ModelAndView modelAndView = new ModelAndView("redirect:/tips.jsp"); //这里为重定向
ModelAndView modelAndView = new ModelAndView("/tips.jsp"); //这里为转发
return modelAndView;
}
}
当方法返回值为String或ModelAndVIew时,如果返回值为null,页面会跳转到访问接口的路径,前端看到的页面是空的。
控制器响应异步请求
异步请求:AJAX请求。
控制器方法的返回类型设置为响应给ajax请求的对象类型。
在控制器方法前添加@ResponseBody注解,将返回的对象转换为JSON响应给AJAX请求。
如果一个类的所有方法都是处理的AJAX请求,那么可以把@ResponseBody添加到类的上面,这样所有的方法都默认处理AJAX请求【加上之后类的所有方法都只能处理AJAX异步处理了】,返回的都是类的JSON数据,所有方法前面都不需要加@ResponseBody注解了。
后端接收前端传过来的对象的JSON,打印后返回一个对象数组的JSON
@Controller
@RequestMapping("/book")
public class BookController {
//接收请求体的数据,并把Books数组转为JSON后转发回去
@RequestMapping("/update")
@ResponseBody
public List<Book> update(@RequestBody Book book) {
System.out.println("book----update");
System.out.println(book);
List<Book> books = new ArrayList<>();
books.add(new Book());
books.add(new Book());
return books;
}
}
后端传到前端对象的JSON格式,再从后端接收JSON格式的数据并打印出来
let obj = {};
obj.name = "java";
obj.author = "张三";
obj.price = 3.33;
$.ajax({
url: "book/update",
type: "post",
contentType: "application/json",
dataType: "json", //接收到返回值为的JSON
data: JSON.stringify(obj),
success: function (result) {
console.log(result);
}
})
控制器相应同步请求的数据传递
对于同步请求的转发响应,我们可以传递参数到转发的页面。
同步提交必须要转发,不转发不能传值。
返回类型为String:
在控制器方法中定义一个Model类型的参数。
在return页面之前,向model中添加键值对,添加的键值对就会传递到转发的页面。
接收前端同步请求后,让前端跳转页面,并向跳转的页面传递值
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add2")
public String addBook2(@RequestParam("name") String name,
@RequestParam("author") String author,
@RequestParam("price") Double price,
Model model) {
System.out.println("book---add");
System.out.println(name + " " + author + " " + price);
model.addAttribute("xin", "123");
model.addAttribute("book", new Book());
return "/tips.jsp";
}
}
tips.jsp页面代码,这里用EL表达式接受,别问我怎么用HTML接收,我也不知道。。。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>tips</title>
</head>
<body>
<h1 style="color: red">hello world</h1>
<hr/>
${xin}
<hr/>
${book}
</body>
</html>
返回类型为ModelAndView:
处理完前端请求后把要返回的地址写到ModelAndView中,
还可以把键对值写到ModelAndView中,把值传到新的页面中,前端接收方式与上一个一样
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add3")
public ModelAndView addBook3(@RequestParam("name") String name,
@RequestParam("author") String author,
@RequestParam("price") Double price) {
System.out.println("book---add");
System.out.println(name + " " + author + " " + price);
ModelAndView modelAndView = new ModelAndView("/tips.jsp");
modelAndView.addObject("xin", "heihei");
modelAndView.addObject("book", new Book());
return modelAndView;
}
}
解决中文乱码问题
乱码出现的原因:前端的编码,传输中的编码,后端的编码不一致造成的。
前端编码
JSP页面
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8"%>
HTML页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"></head>
<body></body>
</html>
服务器编码
这里用的是Tomcat。
设置Tomcat的编码方式
在Tomcat/conf/server.xml中大概在69行,添加"URIEncoding="UTF-8",设置默认编码为UTF-8。
设置SpringMVC的编码方式
在web.xml中配置SpringMVC编码过滤器的编码方式。
在<web-app><web-app/>标签中添加。
<!--把SpringMVC的过滤器加载进来-->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置编码器的编码-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<!--开启强制编码-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
日期格式处理
如果前端需要输入日期数据,在控制器中转换成Date对象,SpringMVC要求前端输入的日期格式必须要"yyyy/MM/dd"。
如果甲方要求日期格式必须是指定的格式,而这个指定格式SpringMVC不接受,那么就处理一下。
创建自定义类型转换器
public class MyDateConverter implements Converter<String, Date> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
@Override
public Date convert(String s) {
Date date= null;
try {
date = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
配置自定义类型转换器
在SpringMVC的配置文件中配置。
<!--开启mvc注解配置,并配置自定义日期转换器-->
<mvc:annotation-driven conversion-service="converterFactory"/>
<!--自定义类型转换器-->
<bean id="converterFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="xin.students.controllers.utils.MyDateConverter"/>
</set>
</property>
</bean>
扩展
在@Controller类方法的形参中添加HttpServletResponse或者HttpServletRequest,SpringMVC是会自动注入的。
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/download")
//HttpServletResponse response, HttpServletRequest request会被String自动注入
public void download(String fileName,HttpServletResponse response, HttpServletRequest request){
}
}
扩展
@Controller与ResponseBody可以合写为@RestController
@RestController要与@Controller一起使用
@RestController
@RequestMapping("/books")
public class MsgServiceImpl {
}