Java入门之SpringMVC(全网最详细)
目录
1.SpringMVC来源:
其实它的来源很好说,一切故事的开始要从一个需求开始,大家可以去看看我的javaweb的入门有说过servlet的来源是什么,其实springmvc的来源就是servlet,springmvc只是替代了做url和对应servlet类的映射,servlet类的里面doGet和doPost方法书写这两步,其他的就没有了,所以来源总结一句话:springmvc的来源是servlet中请求的映射和servlet对response和request对象的操作的集合体。
其实对应serverlet的传统的步骤分别是
1.new servlet类=把类放入spring容器
2.做xml的映射=initialserverlet的类书写和servlet类里面的@requestmapping 和 @postmapping的书写
3.doGet 和 doPost方法的书写=servelt 类里面的方法的书写
4.对response和request对象的操作=加上@response标签
5.操作response对象= 传参和入参在servelt类里面的操作
之前写的博客参考:
Java之入门JavaWeb_java开发网站需要哪些知识-CSDN博客
2.SpringMVC的本质:
其实在来源也写了,它就是servlet中两个步骤的简化模型封装。
3.SpringMVC的使用方法:
3.1入门案例:
既然他是servlet两个步骤的简化,就对照servlet的步骤来写,第一步是写请求和serlvet类的映射,第二步是写servlet类。
而springmvc其实就是把这两步整合在了一个类,映射用标签来实现,servlet类用类和标签一起来实现:
pom.xml:
<?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>com.tang</groupId>
<artifactId>TestSpringMVC</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Test Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-servlet-api -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>10.0.4</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.11</version>
</dependency>
</dependencies>
<build>
<finalName>TestReview</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
关键就是如下三个依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
SpringMVC控制类书写:
package com.tang.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SpringMVC {
@RequestMapping("/getname")
@ResponseBody
public String getName(){
System.out.println("your name is eddie");
return "{'info':'SpringMVC'}";
}
@RequestMapping("/getage")
@ResponseBody
public String getage(){
System.out.println("your age is 13");
return "{'age':'13'}";
}
}
SpringMV加载控制和业务bean的类的书写:
package com.tang.test;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMVC.class);
return ctx;
}
}
SrpingConfig类的书写:
package com.tang.test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.tang")
public class SpringConfig {
}
测试结果:
测试结果1:
测试结果2:
简化SpringMV加载控制和业务bean的类的书写:
简化对比:
如上的ServletContainerInitConfig还是过于复杂,所以我们就还是进行一个简化:
这里需要改这个类的两个东西,一个是改继承的类,之前是: extends AbstractDispatcherServletInitializer
后面我们要改为 extends AbstractAnnotationConfigDispatcherServletInitializer。
第二个就是重写的方法也不一样:
之前是这三个方法:
后续简化后是如下三个方法:
简化后的类的书写如下:
package com.tang.test;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMVC.class};
}
}
4.SpringMVC的请求和响应:
4.1SpringMVC的工作流程:
如下截图来自于在听黑马程序员的课的截图:
4.2浏览器和servlet的传参的对应的书写:
4.2.1为什么要学习传参:
首先在了解传参的对应的书写的时候,希望大家回顾一下http协议,我们为什么要有传参,因为浏览器的请求有请求得到数据,有请求传入数据,修改数据和更改数据,那么我们可能会带需要查询的参数,和需要传入的数据给到请求,而此时这些请求的数据怎么和servlet对应呢,其实就是通过servlet这个类里面的方法的response对象和request对象里面的属性来和这些一一对应,后续由于我们用springMVC来简化servlet后,我们就用springmvc里面写的方法的传参和请求里面的数据一一对应,但是由于请求的数据不同,有时候有基本的数据,字符串,数字等,有时有类,有json的数据,有日期的数据。那么我们的传参也会进行改变,所以我们就需要学习如下的内容。简而言之,浏览器的请求的参数需要和我们servlet的方法的传参一致。这样就可以实现请求和我们方法的操作一致。
4.2.2传参种类:
普通参数:
url:http://localhost:8080/TestSpringMVC/getname?name=eddie&age=18
Servlet方法:
@RequestMapping("/getname")
@ResponseBody
public String getName(String name,int age){
System.out.println("show your name is " + name + "and your age is " + age);
return "{'info':'Spring'}";
}
url:http://localhost:8080/TestSpringMVC/getjob?name=13&age=18
Servlet方法:
@RequestMapping("/getjob")
@ResponseBody
public String getJob(@RequestParam("name")String work, int age){
System.out.println("show your job is " + work + "and your age is " + age);
return "{'info':'Spring'}";
}
//RequestParam 当url传参名和实际传方法参名不对应时 可以把形参名对应成实际url传参名
POJO参数:
url:http://localhost:8080/TestSpringMVC/getKids?name=eddie&age=19
方法:
@RequestMapping("/getKids")
@ResponseBody
public String getKids(Kid kid){
System.out.println("show your job is " + kid.getName() + "and your age is " + kid.getAge());
return "{'info':'Spring'}";
}
嵌套pojo参数:
url:http://localhost:8080/TestSpringMVC/getKids?name=eddie&age=19&address.province=sichuan&address.longage=888
方法;
@RequestMapping("/getKids")
@ResponseBody
public String getKids(Kid kid){
System.out.println("show your job is " + kid.getName() + "and your age is " + kid.getAge() + kid.getAddress().getProvince() +kid.getAddress().getLongAge);
return "{'info':'Spring'}";
}
public class Kid {
private String name;
private int age;
private Address address;
public Kid (){
}
public class Address {
private String province;
private int longAge;
public Address(){
}
数组参数:
url:http://localhost:8080/TestSpringMVC/getBoys?boys=1&boys=2&boys=3
方法:
@RequestMapping("/getBoys")
@ResponseBody
public String getBoys(int[] boys){
for(int i : boys){
System.out.println(i);
}
return "{'info':'Spring'}";
}
集合参数:
url
http://localhost:8080/TestSpringMVC/getBoys?boys=eddie&boys=marry&boys=nono
方法:
@RequestMapping("/getBoys")
@ResponseBody
public String getKids(@RequestParam List<String> boys){
for(String i : boys){
System.out.println(i);
}
return "{'info':'Spring'}";
}
//这里需要注意的是这里的一个RequestParam 可以把List对应成数据和浏览器的数据对应
Json数据:
在讲json数据前,做一个小科普: json数据就两种,一个是对象,一个是数组,对象的描述方式是{key:value} ,
数组就是[{},{}]这种形式,对象是{},数组是[]包裹。
json数据其实也分为几种:
前面说了其实json数据就是两种,第一种就是对象,而js对象其实就是key value来对应。用{}来装,用“”,““来进行对应,第二种就是数组[],数组里面可以包含多个对象,格式也是用,隔开,数组元素可以是对象也可以是普通数据。
那么传入json数据时,我们底层如何对应呢?如下:
第一种:json数组数据:
1.SpringConfig的配置:
@EnableWebMvc
2.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
3.
4.
//这里的重点是这个RequestBody这个地方,这里其实就是要填写 才能把json数组作为数组传入方法。
@RequestMapping("/getParameters")
@ResponseBody
public String getParameters(@RequestBody List<String> parameter){
System.out.println(parameter);
return "{'info':'Json'}";
}
第二种:json对象数据:
传参:
SpringMVC类的书写:
@RequestMapping("/getJsonUsers")
@ResponseBody
public String getJsonUsers(@RequestBody User user){
System.out.println(user);
return "{'info':'Json2'}";
}
第三种:json数组中含有多个对象:
传参:
springMVC配置:
@RequestMapping("/getJsonUsers")
@ResponseBody
public String getJsonUsers(@RequestBody List<User> users){
System.out.println(users);
return "{'info':'Json2'}";
}
其实总结一下:
这里很想 MyBatis里面的Mapper的pojo的类,List<User>就对应数据库的几列数据,而一个类就代表一列数据。
而Json的对象,一个对象就代表一列数据,一个数组对象就代表多列数据。
日期参数对象:
和json一样,首先知道日期的格式有哪些:
2023-09-24
2023/09/24
09/24/2023
传参:
http://localhost:8080/TestSpringMVC/getDateParameter?date=2011/09/33&date1=2022-09-01&date2=2022/09/21 9:23:24
SpringMVC的配置:
@RequestMapping("/getDateParameter")
@ResponseBody
public String getDateParameter( Date date,@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1, @DateTimeFormat(pattern ="yyyy/MM/dd HH:mm:ss") Date date2){
System.out.println(date);
System.out.println(date1);
System.out.println(date2);
return "{'info','Date'}";
}
结果:
4.2.3总结:
@RequestBody 用于把json数据传入成对应的类,list 类 ,
@RequestParameter 用于把集合参数传入成对应的集合
@DateTimeFormat(pattern = "yyyy-MM-dd") 用于把时间参数传入对应的格式
4.3响应:
首先我们响应的东西有哪些,有页面数据,文本数据,类对象。
首先:
页面数据的返回:
这里的重点是了解@ResponseBody这个标签,他们把我们想要传出得东西转换成对应格式传出 比如加了@ResponseBody,则前面写String 他就转为string传出去,是类就转json对象,是数组就转数组
//响应页面
@RequestMapping("/getPage")
public String getPage(){
return "text.jsp";
}
//响应文本
@RequestMapping("getText")
@ResponseBody
public String getText(){
return "response text";
}
//响应json对象
@RequestMapping("/getJson")
@ResponseBody
public User getJson(){
User u = new User();
u.setName("hello");
u.setAge(22);
return u;
}
5.Restful编码风格的书写:
5.1概念:
“ 动作+路径 ” 来代替不同的传参和底层servlet的这种资源的访问形式叫做rest, 用这种形式访问叫做restful l代码风格
5.2使用:
Users 带s表示模块,表示此类资源而非单个资源。 数字代表传入资源 post 增 delete 删 put 改 get 查
5.2.1增删改查:
package com.tang.testspring;
import com.tang.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SpringMVCRestful {
//增加数据
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String sava(){
System.out.println("save data to mysql");
return "{'data','mysql'}";
}
//删除数据
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("delete data to mysql from id = " + id);
return "{'data','delete'}";
}
//修改数据
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(User user){
System.out.println(user);
return "{'data','update'}";
}
//查询数据
@RequestMapping(value = "/users/{id}",method = RequestMethod.GET)
@ResponseBody
public String get(@PathVariable Integer id){
System.out.println("get data from mysql");
return "{'data','get'}";
}
}
5.3简化SpringMVC的Restful接口开发:
其实就是简化了三个东西,
一个是 controller 和 responsebody合成一个注解叫做 restcontroller,
二个在就是直接把requestmapping提出来到类的上面,
三个把方法简化成 postmapping , deletemapping , putmapping, getmapping,方法里面记得加上id
直接上代码:
package com.tang.testspring;
import com.tang.pojo.User;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class SpringMVCRestful {
@PostMapping
public String save(){
System.out.println("save data");
return "{'data','save'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable String id){
System.out.println("delete data");
return "{'data','delete'}";
}
@PutMapping
public String update(User usr){
System.out.println("save data");
return "{'data','update'}";
}
@GetMapping("/{id}")
public String get(@PathVariable String id){
System.out.println("get data");
return "{'data','get'}";
}
}
5.4用SpringMVC的Restful开发案例:
5.4.1配置前端界面以及放通前端界面的显示:
package com.tang.testspring;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringPageConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
5.4.2调通SpringMVC和访问url
前端代码:
<!DOCTYPE html>
<html>
<head>
<!-- 页面meta -->
<meta charset="utf-8">
<title>SpringMVC案例</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="../plugins/elementui/index.css">
<link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="../css/style.css">
</head>
<body class="hold-transition">
<div id="app">
<div class="content-header">
<h1>图书管理</h1>
</div>
<div class="app-container">
<div class="box">
<div class="filter-container">
<el-input placeholder="图书名称" style="width: 200px;" class="filter-item"></el-input>
<el-button class="dalfBut">查询</el-button>
<el-button type="primary" class="butT" @click="openSave()">新建</el-button>
</div>
<el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
<el-table-column type="index" align="center" label="序号"></el-table-column>
<el-table-column prop="type" label="图书类别" align="center"></el-table-column>
<el-table-column prop="name" label="图书名称" align="center"></el-table-column>
<el-table-column prop="description" label="描述" align="center"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" size="mini">编辑</el-button>
<el-button size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination class="pagiantion" @current-change="handleCurrentChange"
:current-page="pagination.currentPage" :page-size="pagination.pageSize"
layout="total, prev, pager, next, jumper" :total="pagination.total">
</el-pagination>
</div>
<!-- 新增标签弹层 -->
<div class="add-form">
<el-dialog title="新增图书" :visible.sync="dialogFormVisible">
<el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right"
label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="图书类别" prop="type">
<el-input v-model="formData.type" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="图书名称" prop="name">
<el-input v-model="formData.name" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="描述">
<el-input v-model="formData.description" type="textarea"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="saveBook()">确定</el-button>
</div>
</el-dialog>
</div>
</div>
</div>
</div>
</body>
<!-- 引入组件库 -->
<script src="../js/vue.js"></script>
<script src="../plugins/elementui/index.js"></script>
<script type="text/javascript" src="../js/jquery.min.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
var vue = new Vue({
el: '#app',
data: {
dataList: [],//当前页要展示的分页列表数据
formData: {},//表单数据
dialogFormVisible: false,//增加表单是否可见
dialogFormVisible4Edit: false,//编辑表单是否可见
pagination: {},//分页模型数据,暂时弃用
},
//钩子函数,VUE对象初始化完成后自动执行
created() {
this.getAll();
},
methods: {
// 重置表单
resetForm() {
//清空输入框
this.formData = {};
},
// 弹出添加窗口
openSave() {
this.dialogFormVisible = true;
this.resetForm();
},
//添加
saveBook() {
axios.post("/TestSpringMVC/books", this.formData).then((res) => {
});
},
//主页列表查询
getAll() {
axios.get("/TestSpringMVC/books").then((res) => {
this.dataList = res.data;
});
},
}
})
</script>
</html>
后端BookController代码:
package com.tang.controller;
import com.tang.pojo.Book;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String sava(@RequestBody Book book){
System.out.println("this is the new book " + book);
return "{'info','saveName'}";
}
@GetMapping
public List<Book> getAll(){
System.out.println("this is a get all method");
List<Book> books = new ArrayList<>();
Book booka = new Book();
booka.setDescription("a little yellow");
booka.setId("a");
booka.setName("yellowbook");
booka.setType("newbook");
Book bookb = new Book();
bookb.setType("oldbook");
bookb.setId("b");
bookb.setName("bulebook");
bookb.setDescription("a little blue");
books.add(booka);
books.add(bookb);
return books;
}
}