本篇内容:SpringMVC入门到入坟 一站式基础及进阶——囊括面试点与初学基础——从0到1
文章专栏:SSM入门到入坟——一站式基础以及进阶栏目
更新周期:2022年1月15日~2022年1月21日
最近更新:2022年1月14日 Spring入门到入坟 一站式基础及进阶——囊括面试点与初学基础——源码分析——从0到1
个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ)
点赞 收藏 ⭐留言 一键三连 关爱程序猿,从你我做起
吃饭睡觉敲代码,可爱又迷人的小付又又又来了~这是SSM框架中一站式到进阶的最后一篇文章
了吧(学习框架思想,理解记忆知识的最后一篇)、后续本栏目会更新有关于SSM框架的项目实战
以及面试考点
等等一系列文章也会放在里面,如果后续还有时间通读源码的话
,我也会尝试像大佬们一样手撕Spring
、希望能有那一天吧!冲冲冲,话不多说,看文章要紧。
SpringMVC
是隶属于Spring Framework
中的一个模块
,这也就是为什么SpringMVC 无需在通过中间层进行整合
。
SpringMVC 是咱们基于JavaWeb
开发的一个MVC
web框架
。
SpringMVC不局限于单一的视图
技术,可以搭载JSP、Vue等优秀的前端视图页面。
Spring MVC 分离了控制器
、模型对象
、分派器
以及处理程序对象的角色
,这种分离让它们更容易进行定制
。
如图所示:
上述图可以理解当我们把SpringMVC
与Spring和Mybatis整合
就形成了MVC三层模型
、利用SpringMVC进行与前端的视图层与服务器后台的Controller层进行页面交互数据请求
,通过Spring注册组件到IOC容器
当中,调用Service的服务层实际是调用自动注入到bean里面的Mapper
持久化数据库的操作
。
DispatcherServlet
:前端控制器,整个流程控制的中心
,控制其它组件执行
,统一调度
,降低
组件之间的耦合性
,提高
每个组件的扩展性
。
HandlerMapping
:扩展处理器的映射器实现不同的映射方式
,例如:配置文件方式
,实现接口
方式,注解
方式等。
HandlAdapter
:扩展处理器的适配器
,支持更多类型
的处理器,调用处理器传递参数等功能
ViewResolver
:扩展
处理器的视图解析器
,支持更多类型的视图解析
,例如:jsp、freemarker、pdf、excel等。
会先到达DispatcherServlet
这个前端控制器
。DispatcherServlet
会通过HandlerMapping
去寻找处理器映射器
。web.xml
或者通过注解
进行查找到具体的处理器
、如果生成处理器拦截器一并返回给前端控制器DispacherServlet
。先去通过HandlerAdapter进行适配
才能使用得到适配后的Controller。先去调用Service层的业务服务
,拿到
所需的数据与Controller结果进行结合返回ModelAndView
传给前端控制器
。拿着这个东西去找ViewResolver去解析视图
,获得View
。拿到的View
进行数据显示响应给用户
。当你把上述SpringMVC执行流程看完你就知道这个前端控制器主要工作是哪些了
DispatcherServlet主要用作职责调度工作
,本身主要用于控制流程,主要职责如下:
文件上传解析,如果请求类型是multipart
将通过MultipartResolver
进行文件上传解析;
通过HandlerMapping
,将请求映射到处理器
(返回一个HandlerExecutionChain
,它包括一个处理器
、多个HandlerInterceptor拦截器
);
通过HandlerAdapter支持多种类型的处理器
(HandlerExecutionChain中的处理器
);
通过ViewResolver解析逻辑视图名到具体视图
实现,渲染具体的视图等;
如果执行过程中遇到异常将交给HandlerExceptionResolver
来解析。
步骤1:配置pom.xml导入SpringMVC的相关依赖
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.8.M1version>
dependency>
注意:这里额外导入了Spring的相关依赖为了后续操作、其实简单的SpringMVC只需要导入spring-webmvc和servlet的相关依赖就好了
步骤2:配置好web项目,设置好Tomcat服务器
如果不会的建议去看一下:Servlet入门到入坟 一站式基础及进阶——SpringMVC没它都不行 你确定不来看看——囊括初学基础以及进阶
步骤3:进行配置web.xml文件、spring-mvc.xml
web.xml
<servlet>
<servlet-name>HelloSpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>HelloSpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
这就是最简单的springmvc配置在web.xml文件中的
spring-mvc.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
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
">
<mvc:annotation-driven/>
<context:component-scan base-package="com.alascanfu"/>
beans>
这里先用注解自动注册快速上手
步骤4:创建对应的Controller(Servlet)与View(视图)
HelloSpringMVCController.java
@Controller
public class HelloSpringMVCController {
@RequestMapping(value = {"/","/index"},method = {RequestMethod.GET})
public String index(Model model){
model.addAttribute("msg","helloSpringMVC");
return "helloSpringMVC.jsp";
}
}
helloSpringMVC.jsp
<%--
Created by IntelliJ IDEA.
User: 帝白灬黎墨
Date: 2022/1/19
Time: 13:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
HelloSpringMVC
${msg}
步骤5:打开Tomcat服务器进行测试
http://localhost:8080/helloSpringMVC/
web.xml中设置servlet映射的url-pattern中/和/*的区别?
/ 不会匹配到*.jsp
,即:*.jsp不会进入spring
的 DispatcherServlet
类
/* 会匹配*.jsp
,会出现返回jsp视图
时再次进入spring的DispatcherServlet
类,导致找不到对应的controller
所以报404错
。
可以配置/ ,此工程 所有
请求全部由springmvc解析
,此种方式可以实现RESTful
方式,需要特殊处理对静态文件的解析不能由springmvc解析
可以配置.do或.action,所有请求的
url扩展名为.do或.action
由springmvc解析
,此种方法常用
不可以/*
,如果配置了,返回jsp也由springmvc解析
,这是不对的。
字面理解这玩意就是视图解析器
在IOC容器中添加这个组件
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
我们来看看InternalResourceViewResolver
的源码:
public class InternalResourceViewResolver extends UrlBasedViewResolver {}
这个类继承了UrlBasedViewResolver
咱们再进去看看~
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
public static final String REDIRECT_URL_PREFIX = "redirect:";
public static final String FORWARD_URL_PREFIX = "forward:";
@Nullable
private Class<?> viewClass;
private String prefix = "";
private String suffix = "";
}
咱们可以看到其属性prefix前缀
和suffix后缀
进行了页面结果的设置,他下面的设置方法,可以简化我们手动对页面进行访问的地址路径。
源码一上,邪恶退散
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
也没多少30多行的样子~
它可以帮我们设置些什么呢?
设置访问地址请求地址
@AliasFor("value")
String[] path() default {};
设置请求的方法类型
RequestMethod[] method() default {};
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private RequestMethod() {
}
}
这里用到了一个枚举类,标注不同的请求方法类型。
我们通过HttpServletRequest
来进行接收参数
,当页面传值时key=处理请求的方法参数名时进行接收
。
接收方式演示
先构建前端视图层页面:
HelloSpringMVC.jsp
<%--
Created by IntelliJ IDEA.
User: 帝白灬黎墨
Date: 2022/1/19
Time: 13:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
HelloSpringMVC
${msg}
addUser
然后去编写UserController
@Controller
public class UserController {
@RequestMapping(value = "/addUser")
public String addUser(String username, int age, Model model){
System.out.println("addUser被执行了");
model.addAttribute("msg","addUser:username:"+username+",age:"+age);
return "addUser";
}
}
书写addUser.jsp前端页面
<%--
Created by IntelliJ IDEA.
User: 帝白灬黎墨
Date: 2022/1/19
Time: 14:41
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
进行测试数据是否将参数传入Controller层
@Controller
public class UserController {
@RequestMapping(value = "/addUser")
public String addUser(User user, Model model){
System.out.println("addUser被执行了");
model.addAttribute("msg","addUser:username:"+user.getUsername()+",age:"+user.getAge());
return "addUser";
}
}
User.java
public class User {
private String username;
private int age ;
public User() {
}
public User(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
}
@RequestParam
注解进行设置@Controller
public class UserController {
@RequestMapping(value = "/addUser")
public String addUser(@RequestParam(name = "username") String name,@RequestParam(name = "age") int age, Model model){
System.out.println("addUser被执行了");
model.addAttribute("msg","addUser:username:"+username+",age:"+age);
return "addUser";
}
}
接受日期参数时引起的错误
SpringMVC默认支持转换的日期格式为:yyyy/MM/dd
添加依赖
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
<version>2.9.9version>
dependency>
改写控制层
@Controller
public class UserController {
@RequestMapping(value = "/addUser")
public String addUser(User user, @DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday, Model model){
System.out.println("addUser被执行了");
model.addAttribute("msg","addUser:username:"+user.getUsername()+",age:"+user.getAge()+",birthday:"+birthday);
return "addUser";
}
}
ModelMap、Model、HttpServletRequest
**等来存储响应数据。receiveData.java
@RequestMapping("/receiveData")
public String receiveData(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday, HttpServletRequest request, ModelMap map, Model model){
System.out.println("birthday:" + birthday);
request.setAttribute("birth", birthday);
map.addAttribute("modelmapkey",birthday);
model.addAttribute("modelkey",birthday);
return "success";
}
为什么上述格式没有发生改变呢因为小付传入的是非Date格式没有用表单传输
ModelAndView
**来进行数据传输 @RequestMapping("/receiveData")
public ModelAndView test2(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
System.out.println("birthday:" + birthday);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("success");
modelAndView.addObject("mvkey",birthday);
return modelAndView;
}
咱们可以通过request.getSession();
来通过Session域传值。
也可以使用注解@SessionAttributes("key值")
与ModelMap 相互结合使用
可以向其添加多个SessionKey值 例如: @SessionAttributes({"key1","key2"})
清除Session域数据
通过SessionStatus
类的方法:status.setComplete();
编写SessionController.java
@Controller
@SessionAttributes("sessionMap")
public class SessionController {
@RequestMapping(value = "/insertData")
public String InsertData(User user, ModelMap map){
map.addAttribute("sessionMap",user);
return "success";
}
@RequestMapping("/out")
public String out(SessionStatus status){
status.setComplete();
return "logout";
}
}
编写success.jsp
<%--
Created by IntelliJ IDEA.
User: 帝白灬黎墨
Date: 2022/1/19
Time: 15:31
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
success
sessionmap:${sessionMap}out
测试
当用户点击/out时会自动清除Session数据
forward将请求转发但是请求地址不变,只是服务器内部的Servlet将请求转发到另一个Servlet上了。
ForwardAndRedirectController.java
@Controller
public class ForwardAndRedirectController {
@RequestMapping("/forwardView")
public String forwardView(){
return "forward:success.jsp";
}
}
通过访问:
http://localhost:8080/helloSpringMVC/forwardView
会将页面跳转到success.jsp
重定向
@RequestMapping("/sendRedirect")
public String sendRedirect(){
return "redirect:success.jsp";
}
当访问/sendRedirect
会被强制重定向到success.jsp页面。
如果采用了model进行传值时还需要注意重定向拼接值的问题
session.invalidate();//用来忽略视图解析器的配置
当出现状态响应码不符合要求时,利用web.xml进行配置对应的错误界面。
<error-page>
<error>404error>
<location>/404.htmllocation>
error-page>
CookieController.java
public class CookieController {
@RequestMapping("/cookie")
public String testCookie(@CookieValue("JSESSIONID")String cookie, HttpServletRequest request){
System.out.println("cookie:"+cookie);
request.setAttribute("cookie",cookie);
return "result";
}
}
会显示当前的Cookie信息的
什么是RestFul风格呢?
我们通常认为其是一种软件架构风格
、是一种设计风格
,而非是标准
,简而言之就是提供了一组设计原则
和约束的条件
。它主要用于用户与服务器之间进行交互
的软件上。基于RestFul风格
设计的软件可以更加的简洁
,更有层次
,更容易与实现缓存等机制
。
换句话来说,就是HTTP协议
里面,四个表示操作方式
的动词
:
POST
DELETE
PUT
GET
分别对应了传统的 增加、删除、修改、查询。
RestFul风格示例
/users/1
HTTPPOST
: 新增用户http://localhost/users?method=insert&id=1
/users/1
HTTPDELETE
: 删除id=1的用户信息http://localhost/users?method=delete&id=1
/users/1
HTTPPUT
: 修改id=1的用户信息http://localhost/users?method=update&id=1
/users/1
HTTPGET
: 查询id=1的用户信息http://localhost/users?method=select&id=1
因为在浏览器form表单只支持GET和POST
,不支持DELETE和PUT请求
,所以说Spring
添加了一个过滤器
,我们可以通过这个过滤器
将请求转换为标准的http方法
,支持GET,POST,DELETE,PUT
请求。
步骤1:添加HiddenHttpMethodFilter配置
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
步骤2:实现增删改查的Controller层控制
@Controller
public class UserController {
@RequestMapping(value = "/users/list/{id}",method = RequestMethod.POST)
public String insertUser(@PathVariable(value = "id") int id){
System.out.println("增加了id = " + id+"的用户数据");
return "list";
}
@RequestMapping(value = "/users/list/{id}",method = RequestMethod.DELETE)
public String deleteUser(@PathVariable(value = "id") int id){
System.out.println("删除了id = " + id +"的用户数据");
return "list";
}
@RequestMapping(value = "/users/list/{id}",method = RequestMethod.PUT)
public String updateUser(@PathVariable(value = "id") int id){
System.out.println("修改了id = " + id +"的用户数据");
return "list";
}
@RequestMapping(value = "/users/list/{id}",method = RequestMethod.GET)
public String getUser(@PathVariable(value = "id") int id){
System.out.println("获得了id = " + id +"的用户数据");
return "list";
}
}
步骤3:实现前端页面测试
list.jsp
<%--
Created by IntelliJ IDEA.
User: 帝白灬黎墨
Date: 2022/1/19
Time: 20:44
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
新增
删除
修改
查询
步骤4:运行服务器 结果演示
依次进行点击
后台响应。
我们要清楚一点:就是DispatcherServlet
作为前端控制器
,我们在web.xml
文件中对其进行配置时,设置成了/
避免了死循环jsp资源
,但是/ 无法拦截jsp资源
,但是它会拦截其他的静态资源
,例如图像
,css样式
,js脚本
等,如果不在jsp文件内部添加
,采用外部导入
的情况下,资源就会被拦截下来
。
<servlet>
<servlet-name>HelloSpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>HelloSpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
那么我们该如何进行配置才可以能获取到静态资源的访问呢?
修改spring-mvc.xml的配置文件
方式1:通过咱们的约束标签来进行简单处理
方式2:直接标签默认约束
<mvc:default-servlet-handler/>
如果Json还没有上过手的尽快去上手哦~
可以看看博主的这篇文章 20分钟带你搞定JSON在Java中的应用:
JSON 前后端交互的信息使者——20分钟速通直接去坟头偷吃贡品
一般采用的是采用添加注解进行返回JSON数据
示例:
直接编写Controller层,并且将返回类型改为@ResponseBody
@Controller
public class JsonController {
@RequestMapping("/getUser")
public @ResponseBody User getUser(){
User alascanfu = new User("Alascanfu", 20);
return alascanfu;
}
}
创建一个拦截器类
HandlerInterceptor
接口preHandle()
拦截器之前
执行。
postHandler()
拦截器结束
执行。
afterCompletion()最后
执行的。
创建拦截器类
MyInterceptor.java
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器开始执行");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器结束执行");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("无论如何都要执行!~");
}
}
spring-mvc中配置拦截器
<mvc:interceptors>
<bean class="com.alascanfu.Interceptor.MyInterceptor"/>
mvc:interceptors>
拦截器一般都是应用
在:
记录
用户请求的日志信息
权限检查
,登录审核权限性能测试
了解过过滤器Filter的同学都知道其是依赖于Servlet的,并且执行的先后顺序也和其在web.xml文件中配置的先后顺序也是有关系的。
如果你对Filter与Listener不是很了解
,强烈建议
你看看博主的这篇文章
:
Filter与Listener 快速上手到实战——一文通透——你真的理解了Filter与Listener了么
而对于多个拦截器他们之间的执行顺序也是跟在SpringMVC的配置文件中定义的先后顺序有关
SpringMVC为我们提供了即插即用
的上传功能
的支持,其主要是依赖通过MultipartResolver
实现。
而SpringMVC在默认的配置中并没有装配MultipartResolver
,所以在默认情况下是无法进行处理文件上传
的。
如果当我们要设置Spring的文件上传的功能
,就必须现在其中配置上传文件解析器
。
步骤1:添加对应的依赖
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
步骤2:编写对应的Controller层
UploadController.java
@Controller
public class UploadController {
@RequestMapping("/upload")
public String upload(MultipartFile myFile, HttpServletRequest request){
//获取上传到的真实路径
String realPath = request.getRealPath("/uploadimg");
System.out.println("realpath = " + realPath);
// 2 得到上传的文件名称
String filename = myFile.getOriginalFilename();
// 3 进行文件上传
try {
myFile.transferTo(new File(realPath + "/" + filename));
} catch (IOException e) {
e.printStackTrace();
}
request.setAttribute("filename",filename);
request.setAttribute("msg","成功!!!");
return "uploadsuccess";
}
}
步骤3:编写对应的上传页面 进行测试
uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
上传
测试结果
文件上传成功!!!
MultipartFile接口中的方法
步骤1:编写对应的Controller
DownloadController.java
@Controller
public class DownloadController {
@RequestMapping("/download")
public ResponseEntity<byte[]> down(String filename, HttpServletRequest request) throws IOException {
//获取服务器存储地址
String realPath = request.getRealPath("/uploadimg");
//得到要下载的文件路径地址
String filePath = realPath + "/" + filename;
//设置响应头信息(数据流)
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// attachment 表示以附件的形式响应给客户端
httpHeaders.setContentDispositionFormData("attachment", URLEncoder.encode(filename, "UTF-8"));
File file = new File(filePath);
// 将文件返回
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), httpHeaders, HttpStatus.CREATED);
return responseEntity;
}
}
步骤2:编写对应的jsp文件
uploadSuccess.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
uploadsuccess.jsp
下载
步骤3:结果演示
哇咔咔~终于完结SSM框架中的SpringMVC框架了
这是小付的二刷框架的心得笔记 与 学习经历
本文全文 23000
字
请放心食用
从开始整理复习到现在五天左右的时间因为囊括了Servlet等前置知识的复习
多注重于实践操作 绝对没有坏处
加油嗷~ 兄弟们