文章目录
前言
本文要记录的大概内容:
使用Spring Boot进行Web项目开发,一般会使用MVC模式,主要包括模型端、视图层和控制端。在使用Spring MVC框架进行Web应用开发时,视图层主要由HTML和JSP承担,Spring Boot提供了一些视图技术支持,官网建议使用Thymeleaf模板引擎。
以下是本篇文章正文内容:
一、Spring MVC的概念以及原理
1.MVC基本概念
MVC全名是Model View Controller。
-
是模型(model)-视图(view)-控制器(controller)的缩写。
-
是一种使用 mvc 设计创建 Web 应用程序的模式。
-
是一种软件设计典范。
-
是软件工程中的一种软件架构模式。
Spring MVC可以理解为对Servlet封装的MVC框架,当前,Java Web技术底层由两种实现方式:一种基于Servlet,一种基于Netty,前者由Spring MVC框架等,后者则有WebFlux。
Spring 的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。
2.MVC原理
- Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型(domain) 或 JavaBean组件(包含数据和行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
- View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
- Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。
目前JAVAWEB开发中的MVC模式一般使用Servlet+JSP+JavaBean的方式进行。
MVC原理是View接收用户输入,发送请求给Controller,Controller调用Module完成具体操作。Module从数据库获取数据并进行业务逻辑判断,然后触发事件也就是间接返回数据给View。
为了加深大家的印象,我们引入MVP与MVC进行对比记忆。是MVC中的C改为P,英文单词全拼为Presenter,读作协调器。MVP即为即模型-视图-协调器。
下面我们将餐馆应用场景与MVC对比。服务员接收客户点菜、给客户上菜,对应的是表示层View,View收集用户输入数据,并展示数据。厨师接收了服务员的请求后,调配各种食材做出一道道香喷喷的菜,对应的是控制层Controller,Controller接收到请求后,调用方法处理这些请求。采购员从商场采购各种食材,并加工整理。采购员对应的是模型层Module,Module从数据库获取数据,并进行业务逻辑加工。
下面我们通过一张图直观地展示它们直接的对比效果。
3.MVC优缺点
MVC优点:
- 耦合性低。MVC 分层有助于管理复杂的应用程序,简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑,提高开发效率。
- 重用性高。
- 生命周期成本低,MVC使开发和维护用户接口的技术含量降低。
- 可维护性高。分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。
MVC缺点
- 不适合小型,中等规模的应用程序。花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。
- 增加系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
- 视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
二、静态资源访问
1.默认配置
ResourceProperties类里面,描述了默认的静态资源映射路径,路径数组描述了相关路径。
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
默认配置的/**会映射到相应路径,访问路径为:
当前项目根路径+/静态资源名。
若在默认的路径下有同名的文件,则访问时优先高的先响应,优先级顺序为:
META-INF/resources > resources > static > public。
根据默认的配置(/**)拦截所有请求,若要访问http://localhost:8080/js/index.js
(1)先去controller中找有没有相对应的请求来处理index.js,有则处理,没有则将请求交给静态资源处理器;
(2)静态资源处理器映射到默认路径下找资源,若找到则显示,若找不到则响应404页面。
2.webjars的使用
webjars可以将前端的各种框架、组件以jar包的形式来使用。webjars将通用的Web前端资源(如js,css等)打成jar包文件,部署在Maven中央仓库上,借助Maven工具对其进行统一依赖管理,保证这些Web资源版本唯一性,升级也比较容易。
1. 在webjars官网查找相关依赖pom文件引用
<!-- 引入webjars依赖 -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
2. 请求访问相关资源
请求META-INF/resources下的/webjars/jquery/3.6.0/下的jquery.js资源:
http://localhost:8080/webjars/jquery/3.6.0/jquery.js
3. 自定义静态资源目录
配置文件中配置
在项目中用户自己定义静态资源加载的位置,需要进行配置才能正常访问到,可以在配置文件中配置或定义一个配置类配置。
项目的resources下创建文件夹mystatic,其中放置静态文件index.js
#设置静态资源的存放路径
spring.resources.static-locations=classpath:/mystatic/
#静态资源的访问路径
spring.mvc.static-path-pattern= /mystatic/**
spring.resources.static-locations=classpath:/mystatic/,classpath:/METAINF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
定义配置类配置
项目的resources目录下,新建文件夹res,在res中创建静态资源文件index2.js
package cn.js.ccit.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/res/**").addResourceLocations("classpath:/res/");
}
}
三、用户请求
1.流程
- 服务器组件(如:tomcat)
- 业务逻辑控制(如:Controller)
- Spring MVC框架容器组件 (如:DispatcherServlet)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.用户请求参数传递
前端页面可以通过表单、url传值、ajax方式等传输数据到控制端
方式0:通过对象 use传值。
不需要添加任何注解
方式1:若传送form表单数据,表单属性名称与Controller中方法参数名保持一致,这时可以不用注解,直接传参。
使用url请求传参,请求的url为:
http://localhost:8080/user?username=aaa&telephone =1111,参数名和方法的属性名保持一致,同样可以将值传输到Controller方法中。
方式2:前端的参数名与Controller方法中的参数名不一致时,可以使用@RequestParam注解来指定URL参数与方法参数之间的映射关系
默认参数值不能为空,否则会出现异常信息,可以使用required属性指明参数是否允许为空
#分别请求以下地址,观察是否报错
//http://localhost:8080/reg2
//http://localhost:8080/user/reqParam?username=22&telephone=444
//http://localhost:8080/user/reqParam
//http://localhost:8080/user/reqParam?username=22
方式3:在RESTFul风格的请求中,常将参数在url中以“/param”的方式进行传递,这时就需要使用@PathVariable注解从url中获取相应的参数值
#注意用户名不输入会报什么错
//http://localhost:8080/user/param
//http://localhost:8080/user/param/tom
//http://localhost:8080/user/param/tom/5555
方式4: 在res下建ajax.js文件
function changeObj(obj) {
let arr = []
for (i in obj) {
arr.push(obj[i])
}
return arr
}
function shuAjax(options) {
let obj1 = {
url: options.url,
method: 'POST',
async: true,
data: options.data,
headers: {
"Content-Type": "application/form-www-urlencoded",
"Content-Type": "application/json"
},
success: function (res) {
console.log(res);
},
error: function (err) {
console.log(err);
}
}
let { url, method, async, data, headers, success, error } = {
...obj1,
...options
}
switch (method.toUpperCase()) {
case 'delete':
}
方式5: 若content-type不是默认的application/x-www-form-urlcoded编码,而是application/json或者application/xml等,则可以使用@RequestBody注解
四、用户响应处理
返回对应视图页面
如html页面或jsp页面,类名使用@Controller注解,即返回对应的页面
返回数据
如JSON格式的数据,若在类名或方法上结合使用了@ResponseBody注解,则返回 JSON格式的数据
可以在类名直接 使用@RestController注解,替代@Controller+@ResponseBody这两个注解
用户注册示例
创建实体类User
package cn.js.ccit.vo;
import lombok.Data;
//实体类
@Data
public class User {
private Integer id;
private String username;
private String pwd;
private String telephone;
}
创建前端页面 userReg.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<form action="/user/getUser" method="post">
username:<input type="text" name="username"><br>
pwd:<input type="password" name="pwd"><br>
tel:<input type="text" name="telephone"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
创建控制端 UserJSONController
/**
*返回用户数据的JSON数据
*/
@RestController
@RequestMapping("user")
public class UserJSONController {
@RequestMapping("getUser")
public User getUser(User user){
return user;
}
}
结果测试
五、Thymeleaf模式
简介
Thymeleaf是一款支持html、xml、text、javascript、css、raw等的模板引擎。
包含两种标记模板模式:html和xml,三种文本模板板式:text、javascript、css,一个无操作模板模式raw。
Thymeleaf基本语法
标准表达式
① 变量表达式
变量表达式实际上是将上下文中包含的变量映射到OGNL表达式或Spring EL表达式,使用格式为:${…},一般用在html标签的元素属性中
<input type="text" name="username" value="admin" th:value="${user.username}">
表示引用用户对象user的username属性,若当前项目服务未启动或user.username值不存在,则文本输入框中显示值admin,若当前项目服务启动并且user.username值存在,则替换静态默认值admin,达到模板引擎动态替换数据。
② 选择(星号)表达式
使用格式为:*{…},一般来说,选择表达式和变量表达式使用效果一样,主要区别是:选择表达式计算所选对象而不是整个上下文。
<div th:object="${user}">
<span th:text="*{username}"></span>
</div>
选择表达式可以和标签th:object一起使用,完成对象属性的简写,表示直接获取object对象中的属性。
表示先取到用户对象user,再获取用户名属性。
③ 消息表达式
消息表达式主要用于模板页面国际化资源的动态替换和展示,使用格式为:#{…}。需要先定义国际化的资源文件(*.properties),再使用#{}格式动态获取资源文件的值。
#英文资源文件resource_en_US.properties:
home.welcome=Welcome!
#中文资源文件resource_zh_CN.properties:
home.welcome=欢迎!
<p th:text="#{home.welcome}">hello</p>
④ 链接网址表达式
链接网址表达式可以把有用的上下文或会话信息添加到URL中,使用格式为:@{…},一般和th:href、th:src等标签结合使用,显示Web应用中的URL链接,支持绝对路径和相对路径。
<a href="detail.html" th:href="@{/user/detail(id=${user.Id})}">show</a>
<a href="/unit4demo /user/detail?id=1}">show</a>
在Thymeleaf的表达式中,可以取各种类型的数据,如:文本(‘one text’,‘hello!’)、数值(0,12.3,4.5)、布尔类型(true,false)、空值(null)。在进行各种运算时,主要有使用“+”进行字符串连接、使用“+、-、*、/、%”等进行算术运算、使用“!、not、and、or”等进行逻辑运算、使用“>、<、>=、<=、==、!=(gt、lt、ge、le、eq、ne)”等进行关系运算、使用“?:”进行条件运算。
常用th标签属性
① th:text属性
th:text是文本替换标签,和另一个th:utext标签相比,th:utext会解析html标签。
#控制端存储数据代码
map.put("message","<h3>test</h3>");
#前台获取代码
<p th:text="${message}">th:text</p>
<p th:utext="${message}">th:utext</p>
② th:object标签
用于表单数据对象绑定,将表单绑定到后台控制端的一个JavaBean参数,一般与th:field一起使用进行表单数据绑定。
#控制端存储数据代码
<form th:action="@{/test2}" th:object="${user}" method="post">
<input type="text" th:field="*{username}"/>
<input type="submit"/>
</form>
th:action表示后台控制器路径,使用@{}表达式进行路径处理
th:field表示绑定数据到表单元素,使用*{username}表示获取user对象中的属性username的值
th:object标签获取后台传过来的上下文中的user对象。
③ th:if和th:unless标签
th:if和th:unless表示条件判断,th:if是当条件成立时显示,th:unless则是条件不成立时显示。
<p th:if="${message}!=null" th:text="${message}">对象不空,则显示信息</p>
<p th:unless="${message}==null" th:text="${message}">对象为空,没有数据显示</p>
这里判断message是否为空对象,若不为空,则显示其内容。th:if的属性值若为非0数值、非0字符值、非“false”“off”“no”字符串等,则认为条件成立。
④ th:switch和th:case标签
th:switch和th:case标签类似于Java的switch-case结构
<div th:switch="${user.role}">
<p th:case="admin">管理员用户</p>
<p th:case="nuser">普通用户</p>
<p th:case="*">其他用户</p>
</div>
用th:switch进行用户角色判断,使用th:case进行匹配,若没有匹配成功,用th:case="*"表示,类似于Java中的default。
⑤ th:each标签
th:each标签用于循环遍历,遍历的对象可以为普通对象、列表、数组等。
#控制端在用户对象中存储了数据,并存在了map中
<div th:each="u:${user}">
<p th:text="${u.id}">id</p>
<p th:text="${u.username}">username</p>
</div>
这里使用th:each迭代获取对象,u代表迭代出的某一个具体对象,使用th:text显示u对象的id和username属性值
#控制端在users列表中存储了user对象,并存在了map中
<tr th:each="user,iterStat: ${users}">
<td th:text="${iterStat.index+1}">index</td>
<th th:text="${user.id}">id</th>
<td th:text="${user.username}">name</td>
</tr>
th:each遍历users列表中的user对象,iterStat表示状态变量,其属性主要有:
- index:当前迭代对象的index(从0开始计算
- count:当前迭代对象的index(从1开始计算)
- size:被迭代对象的大小
- current:当前迭代变量
- even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算)
- first:布尔值,当前循环是否是第一个
- last:布尔值,当前循环是否是最后一个
常用默认对象
Web相关的基本对象
名称 | 描述 |
---|---|
#ctx | 上下文对象 |
#vars | 上下文对象(和#ctx相同, 但是一般用#ctx) |
#locale | 上下文区域设置 |
#request | (仅在Web Contexts中) HttpServletRequest对象 |
#response | (仅在Web Contexts中) HttpServletResponse对象 |
#session | (仅在Web Contexts中) HttpSession对象 |
#servletContext | (仅在Web Contexts中) ServletContext对象 |
参考教材《Spring Boot 项目开发教程》(慕课版)
总结
Web 项目开发主要建立在B/S架构下,是基于浏览器的项目开发。在众多互联网产品中,随处可见Web 项目的身影。Spring Boot 提供了spring-boot-starter-web来为Web项目开发予以支持,为用户提供了嵌入的Tomcat 及Spring MVC的依赖,使用非常方便。