跟随狂神学Java-34,SpringMVC
跟随狂神学Java-34,SpringMVC
joker2yue跟随狂神学Java
作者:joker2yue
链接:https://github.com/Joker2Yue/Joker2Yue-Blog
来源:Github
著作权归原作者所有。商业转载请联系原作者获得授权,非商业转载请注明出处。
第三十四:SpringMVC
“计算机科学并不只是关于计算机,就像天文学并不只是关于望远镜一样。”
SSM:Mybatis+Spring+SpringMVC MVC三层架构
JavaSE:认真学习
JavaWeb:人生学习
框架:研究官方文档,锻炼自学能力,锻炼笔记能力,锻炼项目能力
后续学习:SpringMVC+Vue+SpringBoot+SpringCloud+Linux
什么是MVC
MVC
- 模型(dao,service)Model
- 视图(jsp)View
- 控制器(Servlet)Controller
最经典的MVC就是JSP+Servlet+JavaBean模式
MVVM:M,V,VM(View Model:双向绑定)
Model1时代
- 在早期web的开发中,通常采用的都是Model1
- Model1中,主要分两层,视图层和模型层
优缺点:
- 优点:架构简单,适合小型项目开发
- 缺点:JSP职责不单一,职责过重,不便于维护
Model2时代
Model2把一个项目成三部分,包括视图、控制、模型,即现在的架构
SpringMVC
什么是SpringMVC
概述:
SpringMVC是SpringFramework的一部分,是基于Java实现的MVC的轻量级Web框架
为什么要学习SpringMVC
- 轻量级,简单易学‘
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 我们可以把SpringMVC中要用到的类,注册到Spring中
- 约定优于配置
- 功能强大,RESETful,数据验证,格式化,本地化,主题等
- 简洁灵活
了解SpringMVC
SpringMVC的底层也是Servlet
SpringMVC的原理如下图
SpringMVC执行流程图(实线部分不需要我们做,虚线部分需要我们做)
- DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求
- 我们假设请求的URL为
http://localhost:8080/SpringMVC/hello
- 如上URL拆分成三部分:
- http://localhost:8080 服务器域名
- SpringMVC部署在服务器上的web站点
- hello表示控制器
- 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
- 我们假设请求的URL为
- HandlerMapping为处理器映射,DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找handler
- HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello
- HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello
- HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
- Handler让具体的Controller执行
- Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
- HandlerAdapter将视图逻辑名或逻辑模型传递给DispatcherServlet
- DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
- 最终视图呈现给用户
使用SpringMVC必须配置的三大件
- 处理器映射器
- 处理器适配器
- 视图解析器
两种开发模式
通过XML开发SpingXML
特点:
- 三大件均需手动配置,麻烦
- 容易维护
代码:
web.xml中准备好DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<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">
<!-- 1. 配置DispatcherServlet,这是SpringMVC的核心:请求分发器,前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet 要绑定SpringMVC的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动级别,为1时跟随服务器启动 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 注意:
/ 匹配所有的请求(不包括.jsp)
/* 匹配所有的请求(包括.jsp)
一般写/就行
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>spirngmvc-servlet.xml中准备好处理器映射器、处理器适配器、视图解析器,记得在web.xml中绑定此xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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">
<!-- 其实就是Spring的配置文件 -->
<!-- 处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
</beans>编写页面WEB-INF/jsp/test.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<%--
Created by IntelliJ IDEA.
User: Joker
Date: 2023/7/29
Time: 15:05
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>
${msg}
</body>
</html>配置控制器Controller(实现Controller接口或者是用来@Controller注解的类为一个Controller)HelloController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package com.joker_yue.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 15:20
*/
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
// 业务代码
String result = "Hello SpringMVC!";
modelAndView.addObject("msg", result);
// 视图跳转
modelAndView.setViewName("test"); // 交给springmvc-servlet.xml中的视图解析器,根据其配置,将会自动拼接链接并跳转到/WEB-INF/jsp/test.jsp
return modelAndView; // 必需:返回一个ModelAndView
}
}addObject方法可以设置要返回的对象
setViewName方法可以设置要跳转的页面
在SpringMVC配置文件(springmvc-servlet.xml)中注册bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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">
<!-- 其实就是Spring的配置文件 -->
<!-- 处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- BeanNameUrlHandlerMapping需要根据bean的名字来找 -->
<bean id="/hello" class="com.joker_yue.controller.HelloController"/>
</beans>
通过注解开发SpingMVC
特点:
- 三大件中只需要配置视图解析器,另外两个不需要手动配置
- 没那么容易维护
代码:
注册DispatcherServlet,web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<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">
<!-- 1. 配置DispatcherServlet,这是SpringMVC的核心:请求分发器,前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet 要绑定SpringMVC的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动级别,为1时跟随服务器启动 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 注意:
/ 匹配所有的请求(不包括.jsp)
/* 匹配所有的请求(包括.jsp)
一般写/就行
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>SpringMVC配置文件,springmvc-servlet.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<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">
<!-- 自动扫描包 -->
<context:component-scan base-package="com.joker_yue.controller"/>
<!-- 让SpringMVC不处理静态资源 例如css,js,mp3,mp4等 -->
<mvc:default-servlet-handler/>
<!--
支持MVC注解驱动
在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.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 16:09
*/
// 如果写了这个,那么下面所有请求都要先经过它
public class HelloController {
public String hello(Model model) {
{
// 封装数据
model.addAttribute("msg", "hello");
return "hello";// 会被视图解析器处理
}
}
}前端页面,hello.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<%--
Created by IntelliJ IDEA.
User: Joker
Date: 2023/7/29
Time: 16:08
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>
</body>
</html>
Controller
实现方式一:实现Controller接口
说明
- 实现Controller接口定义控制器是较老的办法
缺点
- 一个控制器中只有一个方法,如果使用多个方法则需要定义多个Controller;定义的方式比较麻烦
注意
- 通过这种方式实现的Controller,是需要在SpingMVC配置文件中将Controller进行注册的
代码
ControllerTest01.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package com.joker_yue.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 16:52
*/
// 只要实现了Controller接口的类,说明它就是一个Controller控制器了
public class ControllerTest01 implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "controller test01");
mv.setViewName("test");
return mv;
}
}springmvc-servlet.xml
1
2<!-- 注册Controller -->
<bean name="/t1" class="com.joker_yue.controller.ControllerTest01"/>
实现方式二:通过注解(最常用)
这四个常用注解都是将类注册为组件
1 | 组件 |
代码:
ControllerTest02.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 17:06
*/
// 代表将会被Spring托管
public class ControllerTest02 {
public String test(Model model) {
model.addAttribute("msg", "controller test02");
return "test";
// return "hello"; // 这样写将会走/WEB-INF/jsp/hello.jsp
}
}
注意
- 被Controller注解所注解的类,其中如果有方法返回值为String,并且有具体的页面可以跳转,那么这个方法将会被视图解析器解析,其中return的返回值为要拼接跳转的页面
- 如果传参有Model,说明将会携带数据
- @RequestMapping可以注解到类和方法上。当注解到类上时,要访问方法,先要经过类上的路径
RestFul风格
什么是restful风格
传统风格
1 | http://localhost:8080/method?add=1&add=2 |
restful
1 | http://localhost:8080/method/add/1/2 |
操作:
现在有一个类,希望实现a+b
1 | package com.joker_yue.controller; |
需要的链接为
1 | http://localhost:8080/add?a=1&b=2 |
而现在我们希望将其改成Restful传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 17:30
*/
public class RestfulController {
// 原来的: http://localhost:8080/add?a=1&b=2
// Restful:http://localhost:8080/add/a/b
public String test1(int a, int b, Model model) {
int res = a + b;
model.addAttribute("msg", "结果为" + res);
return "test";
}
}原来的链接将不可用,现在需要的是
1
http://localhost:8080/add/a/b
我们甚至还可以限定它通过什么方式请求,比如我们这里将其限定为通过GET方式请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 17:30
*/
public class RestfulController {
// 原来的: http://localhost:8080/add?a=1&b=2
// Restful:http://localhost:8080/add/a/b
public String test1(int a, int b, Model model) {
int res = a + b;
model.addAttribute("msg", "结果为" + res);
return "test";
}
}现在它只能通过get方式请求
我们可以使用GetMapping注解来代替RequestMapping请求来达到上述同样的效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 17:30
*/
public class RestfulController {
// 原来的: http://localhost:8080/add?a=1&b=2
// Restful:http://localhost:8080/add/a/b
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public String test1(int a, int b, Model model) {
int res = a + b;
model.addAttribute("msg", "结果为" + res);
return "test";
}
}当然,有GetMapping就肯定有DeleteMapping这些衍生的
1
2
3
4
5
注意:
- 通过Restful风格,可以做到地址栏相同而结果不同,这是由于请求方式不同
优点
- 使路径变得简洁
- 获得参数更加方便,框架会自动进行类型转换
- 通过路径的类型可以约束访问参数,如果路径不一样,则访问不到对应的请求方法
- 安全,原来一定会暴露一些参数
- 高效,支持缓存
重定向和转发
重定向
我们可以使用Servlet的request和response来完成重定向和转发,这种方法就不需要视图解析器了
代码:
1 | package com.joker_yue.controller; |
在return语句中,你可以显式的来告诉这是转发
1 | return "forward:/WEB-INF/jsp/test.jsp"; |
转发
1 | package com.joker_yue.controller; |
处理、提交数据
获取数据
提交的域名称和处理方法的参数名一致
提交数据:
http://localhost:8080/hello?name=joker
处理方法:
1
2
3
4
5
public String hello(String name){
System.out.println(name);
return "hello";
}后台输出:joker
提交的域名称和处理方法的参数名不一致
提交数据
http://localhost:8080/hello?username=joker
处理方法:使用注解@RequestParam
1
2
3
4
5
public String hello({ String name)
System.out.println(name);
return "hello";
}==建议:不管前后端名称一不一样,都加上@RequestParam注解==
提交的是一个对象
实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.joker_yue.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 20:13
*/
public class User {
private int id;
private String name;
private String age;
}提交数据
http://localhost:8080/user/t2?id=1&name=joker&age=19
处理方法
1
2
3
4
5
6
7// 前端接收的是一个对象:id,name,age
// 将会自动匹配字段名,字段不一致将会匹配不到
public String test2(User user) {
System.out.println(user);
return "test";
}后台输出User(id=1, name=joker, age=19)
提交数据
你可以使用Model,这是最常用的
1 | public String test1(Model model) { |
也可以使用ModelAndView
1 | public class HelloController implements Controller { |
还可以使用ModelMap
1 | public String test2(ModelMap model) { |
一些关系
1 | LinkedHashMap |
解决乱码
自己写的过滤器
EncodingFilter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package com.joker_yue.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @author Joker
* @version 1.0
* @date 2023/7/29 21:03
*/
public class EncodeingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}web.xml
1
2
3
4
5
6
7
8<filter>
<filter-name>encodingfilter</filter-name>
<filter-class>com.joker_yue.filter.EncodeingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Spring自带的过滤器
1 | <!-- SpringMVC EncodingFilter --> |
JSON
什么是Json
前后端分离时代:
- 后端部署后端,提供接口,提供数据
- 前端独立部署,负责渲染后端的数据
前后端数据约定:
- JSON,JavaScript Object Notation,JS对象标记,是一种轻量级的数据交换格式,目前使用广泛
JSON的特性:
- 采用完全独立于编程语言的文本格式来储存和表示数据
- 简洁和清晰的层次结构是的JSON成为理想的数据交换语言
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率
JSON的使用
在JavaScript中,一切都是对象,因此,任何JavaScript支持的类型都可以通过JSON来表示,例如字符串,数字,对象,数组等。看看它的要求和语法格式:
- 对象表示为键值对,数据由逗号分隔
- 花括号保存为对象 {}
- 方括号保存为数组 []
JSON键值对是用来保存JavaScript对象的一种方式,和JavaScript对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “ ” 包括,使用冒号 : 分割,然后紧接着值:
1 | {"name":"joker"} |
JSON是JavaScript对象的字符串表示法,它使用文本表示一个JS对象的信息本质是一个字符串
1 | var obj ={a:'hello',b:'world'}; //这是一个对象,注意键名也是可以使用引号包裹的 |
JSON和JavaScript对象互转
要实现从JSON字符串转换为JavaScript独享,使用JSON.parse()方法
1
2var obj = JSON.parse('{"a": "hello", "b": "world"}');
// 结果为{a:'hello',b:'world'}要实现从JavaScript对象转为JSON字符串,使用JSON.stringify()方法
1
2var json = JSON.stringify({a:'hello',b:'world'});
// 结果为'{"a":"hello" , "b":"world"}'
小测试:
1 |
|
Controller返回JSON数据-Jsckson
- Jackson是目前比较好的json解析工具
- 当然,解析工具不止这一个,比如还有阿里巴巴的fastjson等
我们使用Jackson来演示
导入配置
1
2
3
4
5<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>导入配置:springmvc-servlet.xml,web.xml
编写实体类和Controller
实体类:User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package com.joker_yue.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 14:34
*/
public class User {
private String name;
private int age;
private String sex;
}Controller:UserController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32package com.joker_yue.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.joker_yue.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 14:35
*/
public class UserController {
//只要你加@ResponseBody,就不会走视图解析器,会直接返回一个字符串
public String json1() throws JsonProcessingException {
// 创建一个对象
User user = new User("joker", 18, "男");
// jackson,ObjectMapper
ObjectMapper mapper = new ObjectMapper();
String value = mapper.writeValueAsString(user);
return value;
}
}
我们可以在@RequestMapping上声明返回的数据类型和编码格式:
1 |
如果在类上标注@RestController,那么此类下所有方法将不会走视图解析器,那么返回值是String的方法可以方便的返回JSOn字符串。
1 | package com.joker_yue.controller; |
时间格式化:
1 |
|
1 |
|
我们可以将重复的代码部分实现为一个Util类
1 | package com.joker_yue.utils; |
Controller返回JSON数据-FastJson
1 |
|
SSM整合
Mybatis层
数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16CREATE DATABASE `ssmbuild`;
USE `ssmbuild`;
CREATE TABLE `books`(
`bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT(11) NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
KEY `bookID`(`bookID`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`) VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');Maven
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93<!-- 依赖:junit,数据库驱动,连接池,servlet,jsp,mybatis,mybatis-spring,spring -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
<!-- Servlet,JSP -->
<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.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.29</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.29</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
<build>
<finalName>SSMBuild</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>pojo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.joker_yue.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 16:04
*/
public class Books {
private int bookID;
private String bookName;
private int bookCount;
private String bookDetail;
}dao层Maper接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package com.joker_yue.dao;
import com.joker_yue.pojo.Books;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 16:16
*/
public interface BookMapper {
// 增加一本书
int addBook(Books books);
// 删除一本书
int deleteBookById(int id);
// 更新一本书
int updateBook(Books books);
// 查询一本书
Books queryBookById(int id);
// 查询全部的书
List<Books> queryAllBooks();
}接口对应的Mapper.xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<mapper namespace="com.joker_yue.dao.BookMapper">
<insert id="addBook" parameterType="Books">
insert into ssmbuild.books (bookName, bookCounts, detail)
values (#{bookName}, #{bookCount}, #{bookDetail})
</insert>
<delete id="deleteBookById" parameterType="int">
delete from ssmbuild.books where bookID = #{bookID}
</delete>
<update id="updateBook" parameterType="Books">
update ssmbuild.books
set bookName = #{bookName}, bookCounts = #{bookCount}, detail = #{bookDetail}
where bookID = #{id}
</update>
<select id="queryBookById" parameterType="int" resultType="Books">
select *
from ssmbuild.books
where bookID = #{id}
</select>
<select id="queryAllBooks" resultType="com.joker_yue.pojo.Books">
select * from ssmbuild.books
</select>
</mapper>service层的接口和实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.joker_yue.service;
import com.joker_yue.pojo.Books;
import java.util.List;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 16:42
*/
public interface BookService {
// 增加一本书
int addBook(Books books);
// 删除一本书
int deleteBookById(int id);
// 更新一本书
int updateBook(Books books);
// 查询一本书
Books queryBookById(int id);
// 查询全部的书
List<Books> queryAllBooks();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package com.joker_yue.service;
import com.joker_yue.dao.BookMapper;
import com.joker_yue.pojo.Books;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @author Joker
* @version 1.0
* @date 2023/7/30 16:45
*/
public class BookServiceImpl implements BookService {
// Service调用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 queryBookById(int id) {
return bookMapper.queryBookById(id);
}
public List<Books> queryAllBooks() {
return bookMapper.queryAllBooks();
}
}
Spring层
Spring整合Mybatis的相关配置文件,daoc层,spring-dao.xml。我们这里数据源使用c3p0连接池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<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
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 关联数据库配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 2. 连接池
dbcp: 半自动化操作
c3p0: 自动化操作,自动加载配置文件并自动设置到对象中
druid、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>
<!-- 3. sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定Mybatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4. 配置dao接口扫描包,动态的实现了Dao接口可以注入到spring容器中 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 要扫描的包 -->
<property name="basePackage" value="com.joker_yue.dao"/>
</bean>
</beans>Spring整合service层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 扫描service下的包 -->
<context:component-scan base-package="com.joker_yue.service"/>
<!-- 2. 将所有业务类注入到spring,可以通过配置或者注解实现 -->
<bean id="bookServiceImpl" class="com.joker_yue.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
<!-- 3. 声明式事务配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 4. AOP横切事务 -->
</beans>
Spring层
web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<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">
<!-- DispatcherServlet 核心Servlet -->
<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>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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Session自动超时 -->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>spring-mvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 注解驱动 -->
<mvc:annotation-driven/>
<!-- 2. 静态资源过滤 -->
<mvc:default-servlet-handler/>
<!-- 3. 扫描包:Controller -->
<context:component-scan base-package="com.joker_yue.controller"/>
<!-- 4. 视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Ajax
什么是Ajax
Asynchronous JavaScript and XML(异步的JavaScript和XML)
- 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术
- 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术
- 2005年Google通过其GoogleSuggest使Ajax变得流行起来。它能够帮你自动完成搜索单词
- GoogleSuggest使用ajax创造出动态性极强的web界面,当你在谷歌的搜索框输入文本的时候,JavaScript会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表
- 传统的网页(即不使用Ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页
- 使用ajax的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新
- 使用ajax,用户可以创建接近本地桌面应用的直接、可高用、更丰富的web用户界面
jQuery
jQuery是一个库,有js的大量函数(方法)
js:
- 函数:闭包
- Dom
- id,name,tag
- create,remove
- Bom
- Window
- document
ES6:import,require
1 | <%-- |
1 | package com.joker_yue.controller; |
Ajax异步获取请求
1 | package com.joker_yue.controller; |
1 | <%-- |
拦截器
拦截器类似于Servlet中的过滤器
过滤器
- servlet规范中的一部分,任何javaweb工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行过滤
拦截器
- 是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的
使用拦截器
TestController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Joker
* @version 1.0
* @date 2023/8/1 15:22
*/
public class TestController {
public String test(){
System.out.println("TestController");
return "ok";
}
}MyInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35package com.joker_yue.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Joker
* @version 1.0
* @date 2023/8/1 15:29
*/
public class MyInterceptor implements HandlerInterceptor {
// return true:放行,执行下一个拦截器
// return false:拦截
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===========preHandle===========");
return true;
}
// 日志
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===========postHandle===========");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===========afterCompletion===========");
}
}applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11
12<!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<!--
/ 过滤所有请求
/* 过滤当前请求
/**过滤所有请求
-->
<mvc:mapping path="/**"/>
<bean class="com.joker_yue.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
文件上传
前端表单要求
必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<%--
Created by IntelliJ IDEA.
User: Joker
Date: 2023/8/1
Time: 16:34
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>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
后端要求
使用comons-io
Maven配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Java Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JavaServer Pages (JSP) API -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- JavaServer Pages Standard Tag Library (JSTL) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>applicationContext.xml
1
2
3
4
5
6
7
8
9<!-- 文件上传配置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jsp的pageEncoding属性一致,以便正确读取表单中的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- 文件上传大小限制,单位为字节 (10MB=10485760) -->
<property name="maxUploadSize" value="10485760"/>
<!-- 缓冲 -->
<property name="maxInMemorySize" value="40960"/>
</bean>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79package com.joker_yue.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
/**
* @author Joker
* @version 1.0
* @date 2023/8/1 16:35
*/
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
public String fileUpload( CommonsMultipartFile file , HttpServletRequest request)throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.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";
}
/*
* 采用file.Transto 来保存上传的文件
*/
public String fileUpload2( 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";
}
}
文件下载
1、设置 response 响应头
2、读取文件 – InputStream
3、写出文件 – OutputStream
4、执行操作
5、关闭流 (先开后关)
代码:
1 |
|