文章目录
Spring boot
什么是Spring boot
简介
- 简化 Spring 应用程序的创建和开发过程
- 抛弃了繁琐的 xml 配置过程,采用大量的默认配置简化以及注解反射
- 直接使用 java main 方法启动内嵌的 Tomcat 服务器运行 Spring Boot 程序,不需要部署 war 包文件
特点
1. 独立运行的 Spring 项目
Spring Boot 可以以 jar 包的形式独立运行,Spring Boot 项目只需通过命令“ java–jar xx.jar” 即可运行。
2. 内嵌 Servlet 容器
Spring Boot 使用嵌入式的 Servlet 容器(例如 Tomcat、Jetty 或者 Undertow 等),应用无需打成 WAR 包 。
3.提供starter简化Maven配置
Spring Boot提供一系列的"starter"项目对象模型(POMS)来简化Maven配置
4.提供大量的自动配置
Spring boot提供大量的自动配置来简化项目的开发,也可以通过配置文件修改默认配置
5.自带应用监控
Spring Boot 可以对正在运行的项目进行监控
6.无代码生成和xml配置
Spring Boot 不需要任何的xml配置即可实现Spring的所有配置
Spring Boot staerter
YAML
YAML 简介
YAML 全称YAML Ain’t Markup Language
- 是一种以数据为中心的标记语言
YAML 工作大致原理
使用YAML作为属性配置文件
- 以 .yml 或 .yaml 后缀名结尾
需要将 SnakeYAML 库添加到 classpath 下,Spring Boot 中的 spring-boot-starter-web 或 spring-boot-starter 都对 SnakeYAML 库做了集成, 只要项目中引用了这两个 Starter 中的任何一个,Spring Boot 会自动添加 SnakeYAML 库到 classpath 下。
YAML 语法
- 使用缩进表示层级关系。
- 缩进时不允许使用 Tab 键,只允许使用空格。
- 缩进的空格数不重要,但同级元素必须左侧对齐。
- 大小写敏感。
server:
port: 端口号
servlet:
context-path: /路径名
YAML 常用写法
字面量写法
name: yohane
对象写法
普通写法
student:
name:yohane
age:15
行内写法
student: {name: yohane,age: 15}
数组写法
普通写法
pets:
-dog
-cat
-panda
行内写法
pets: [dog,cat,panda]
YAML 组织结构
一个 YAML 文件可以由一个或多个文档组成,文档之间使用“—**”作为分隔符,且个文档相互独立,互不干扰。如果 YAML 文件只包含一个文档,则“—”**分隔符可以省略。
---
website:
name: bianchengbang
url: www.biancheng.net
---
website: {name: baidu,url: www.baidu.net}
pets:
-dog
-cat
-pig
---
pets: [dog,cat,pig]
name: "yohane \n lisi"
---
name: 'yohane \n lisi'
配置核心文件
删除properties文件后建立yml配置文件
如果properties配置文件和yml都存在,则以properties为主
Spring Boot Starter Web
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
使用@ResponseBody和@RequestMapping快速配置
@RequestMapping:请求映射
@ResponseBody:请求主体
@ResponseBody
@RequestMapping(value = "/hello")
public String hello(){
return "Hello This the Test";
}
启动SpringBoot,浏览器访问localhost:8080/hello
@RequestMapping
@ResponseBody
@PathVariable
{}来表示他的声明部分
@ResponseBody
@RequestMapping(value = "/getId/{id}")
public String updataProduct(@PathVariable("id")String id){
return "你的用户号: " + id;
}
打开浏览器查看结果
允许定义多个URL变量值
@ResponseBody
@RequestMapping(value = "/getUser/{user}/{pass}")
public String upData(@PathVariable("user")String UserName,@PathVariable("pass")String PassWord){
return "用户名 : " + UserName + " 密码 : " + PassWord;
}
打开浏览器查看结果
匹配正则表达式
@ResponseBody
@RequestMapping(value = "/checkUser/{user:[a-zA-Z0-9_]+}")
public String CheckUser(@PathVariable("user")String UserName){
return "这是一个符合规则的用户名 : " + UserName;
}
打开浏览器查看结果
不符合条件的
符合条件的
不合法的URL不会被处理,而是直接有SpringMVC框架返回404 Not Found
Spring Boot 整合 Mybatis
引入依赖
<!--引入 mybatis-spring-boot-starter 的依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
一般在创建好的spring boot项目中都会存在
配置Mybatis
yml/yaml:
mybatis:
# 指定 mapper.xml 的位置
mapper-locations: classpath:mybatis/mapper/*.xml
#扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
type-aliases-package: net.biancheng.www.bean
configuration:
#默认开启驼峰命名法,可以不用设置该属性
map-underscore-to-camel-case: true
properties
#配置.xml文件路径
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:/com/yang/springbootDemo/mapper/*.xml
#配置模型路径
mybatis.type-aliases-package=com.yang.springbootDemo.model
创建实体类
例子:
@Data
public class Student {
private String id;
private String name;
private int age;
}
可以配合lomck使用,lomck可以参考其它文档
@Data:注解中包含了get,set和toString,所以我们直接在实体类中是@Data注解就可以免了再去手动创建这步骤了。
创建Mapper接口
例子:
@Mapper
public interface UserMapper {
//通过用户名密码查询用户数据
User getByUserNameAndPassword(User user);
}
当 mapper 接口较多时,我们可以在 Spring Boot 主启动类上使用 @MapperScan 注解扫描指定包下的 mapper 接口,而不再需要在每个 mapper 接口上都标注 @Mapper 注解。
创建Mapper映射文件
在配置文件 application.properties/yml 通过 mybatis.mapper-locations 指定的位置中创建 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.biancheng.www.mapper.UserMapper">
<resultMap id="BaseResultMap" type="User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="user_id" jdbcType="VARCHAR" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="password" jdbcType="VARCHAR" property="password"/>
<result column="email" jdbcType="VARCHAR" property="email"/>
</resultMap>
<sql id="Base_Column_List">
id, user_id, user_name, password, email
</sql>
<!--根据用户名密码查询用户信息-->
<!--application.yml 中通过 type-aliases-package 指定了实体类的为了,因此-->
<select id="getByUserNameAndPassword" resultType="User">
select *
from user
where user_name = #{userName,jdbcType=VARCHAR}
and password = #{password,jdbcType=VARCHAR}
</select>
</mapper>
使用 Mapper 进行开发时,需要遵循以下规则:
- mapper 映射文件中 namespace 必须与对应的 mapper 接口的完全限定名一致。
- mapper 映射文件中 statement 的 id 必须与 mapper 接口中的方法的方法名一致
- mapper 映射文件中 statement 的 parameterType 指定的类型必须与 mapper 接口中方法的参数类型一致。
- mapper 映射文件中 statement 的 resultType 指定的类型必须与 mapper 接口中方法的返回值类型一致。
创建Service接口
例子:
public interface UserService {
public User getByUserNameAndPassword(User user);
}
创建实现类
例子:
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User getByUserNameAndPassword(User user) {
User loginUser = userMapper.getByUserNameAndPassword(user);
return loginUser;
}
}
@Service 注解将其以组件的形式添加到容器中
@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作
装配到Controller中
例子:
@Slf4j
@Controller
public class LoginController {
@Autowired
UserService userService;
@RequestMapping("/user/login")
public String doLogin(User user, Map<String, Object> map, HttpSession session) {
//从数据库中查询用户信息
User loginUser = userService.getByUserNameAndPassword(user);
if (loginUser != null) {
session.setAttribute("loginUser", loginUser);
log.info("登陆成功,用户名:" + loginUser.getUserName());
//防止重复提交使用重定向
return "redirect:/main.html";
} else {
map.put("msg", "用户名或密码错误");
log.error("登陆失败");
return "login";
}
}
}
相关的Mybatis的注解
为了解决这个问题,MyBatis 针对实际实际业务中使用最多的“增伤改查”操作,分别提供了以下注解来替换 mapper 映射文件,简化配置:
- @Select
- @Insert
- @Update
- @Delete
详细可参考其它文档
注意:
仔细查看xml和yml等配置文件是否配置错误
出现错误时可在spring boot 日志里查看详细出现错误的类或文件
Spring boot 统一日志框架
Spring Boot 静态资源映射
WebJars映射:
为了页面的美观,Web应用中常会使用大量的js和css,例如 jQuery,Backbone.js 和 Bootstrap 等等
通常我们会将这些资源拷贝到Java Web项目的webapp相应目录下。
可是spring boot项目是以Jar包的形式部署的。
WebJars可以将Web前端资源打成jar包,然后部署到Maven中央仓库,当Spring boot项目需要引入Web前端资源时,只需要WebJars 官网,找到对应的pom依赖即可导入。
Spring Boot 通过 MVC 的自动配置类 WebMvcAutoConfiguration 为这些 WebJars 前端资源提供了默认映射规则
部分源码:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
//WebJars 映射规则
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
通过以上源码可知,WebJars 的映射路径为“/webjars/”,即所有访问“/webjars/”的请求,都会去“classpath:/META-INF/resources/webjars/”查找 WebJars 前端资源。
示例:
在Spring boot项目的pom.xml中添加依赖
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
Spring Boot 项目中引入的 jquery 的 Jar 包结构如下。
默认静态资源映射:
当访问项目中的任意资源(即“/**”)时,Spring Boot 会默认从以下路径中查找资源文件(优先级依次降低):
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
当我们请求某个静态资源(即以“.html”结尾的请求)时,Spring Boot 会先查找优先级高的文件夹,再查找优先级低的文件夹,直到找到指定的静态资源为止。
示例:
在 spring-boot-springmvc-demo1 的 src/main/resources 下的 static 目录中创建一个 hello.html
<!DOCTYPE html>
<html lang="en">
<head></head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<body>
<h1>欢迎您来到</h1>
</body>
</html>
静态首页映射:
静态资源文件夹下的所有 index.html 被称为静态首页或者欢迎页,它们会被被 /** 映射,换句话说就是,当我们访问“/”或者“/index.html”时,都会跳转到静态首页(欢迎页)。
注意,访问静态首页或欢迎页时,其查找顺序也遵循默认静态资源的查找顺序,即先查找优先级高的目录,在查找优先级低的目录,直到找到 index.html 为止。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>
启动 Spring Boot,使用浏览器访问“http://localhost:8080/”
Thymeleaf
简介
Thymeleaf是一款渲染XML/XHTML/HTML5 内容的模板引擎。和JSP,Velocy等模块引擎类似
也可以轻易地与 Spring MVC 等 Web 框架集成
Thymeleaf 最大的特点是,即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面
Thymeleaf与Velocity、FreeMarker 等传统 Java 模板引擎不同
支持HTML原型,因此可以直接被浏览器打开,浏览器会忽略未定义的Thymeleaf 标签属性,展示Thymeleaf模板的静态页面效果
当被Web应用程序访问时,Thymeleaf 通过在 html 标签中,增加额外属性来达到“模板+数据”的展示方式
示例:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:text 为 Thymeleaf 属性,用于在展示文本-->
<h1 th:text="迎您来到Thymeleaf">欢迎您访问静态页面 HTML</h1>
</body>
</html>
当直接使用浏览器打开:
当使用Web应用程序访问时:
注意:
要添加依赖和配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
thymeleaf:
prefix:
classpath: /templates #访问templates下的html则需要配置
cache: false #开发时关闭缓存,不然没法看到实时页面
后台配置映射关系:
@RequestMapping(value = "/toThyShow")
public ModelAndView backThymeleaf(){
ModelAndView mav = new ModelAndView();
mav.setViewName("thymeleafShow");
return mav;
}
查看结果
Thymeleaf的特点
Thymeleaf 模板引擎具有以下特点:
- 动静结合:Thymeleaf 既可以直接使用浏览器打开,查看页面的静态效果,也可以通过 Web 应用程序进行访问,查看动态页面效果。
- 开箱即用:Thymeleaf 提供了 Spring 标准方言以及一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- 多方言支持:它提供了 Thymeleaf 标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、 OGNL 表达式;必要时,开发人员也可以扩展和创建自定义的方言。
- 与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提供了的默认配置,并且还为 Thymeleaf 设置了视图解析器,因此 Thymeleaf 可以与 Spring Boot 完美整合。
Thymeleaf 语法规则
在使用 Thymeleaf 之前,首先要在页面的 html 标签中声明名称空间
xmlns:th="http://www.thymeleaf.org"
Thymeleaf 作为一种模板引擎,它拥有自己的语法规则。Thymeleaf 语法分为以下 2 类:
- 标准表达式语法
- th 属性
Thymeleaf 模板引擎支持多种表达式:
- 变量表达式:${…}
- 选择变量表达式:*{…}
- 链接表达式:@{…}
- 国际化表达式:#{…}
- 片段引用表达式:~{…}
使用 ${} 包裹的表达式被称为变量表达式,该表达式具有以下功能:
- 获取对象的属性和方法
- 使用内置的基本对象
- 使用内置的工具对象
获取对象的属性和方法
使用变量表达式可以获取对象的属性和方法,例如,获取 person 对象的 lastName 属性
${person.lastName}
使用内置的基本对象
使用变量表达式还可以使用内置基本对象,获取内置对象的属性,调用内置对象的方法。 Thymeleaf 中常用的内置基本对象如下:
- #ctx :上下文对象;
- #vars :上下文变量;
- #locale:上下文的语言环境;
- #request:HttpServletRequest 对象(仅在 Web 应用中可用);
- #response:HttpServletResponse 对象(仅在 Web 应用中可用);
- #session:HttpSession 对象(仅在 Web 应用中可用);
- #servletContext:ServletContext 对象(仅在 Web 应用中可用)。
例如,我们通过以下 2 种形式,都可以获取到 session 对象中的 map 属性:
${#session.getAttribute('map')}
${session.map}
使用内置的工具对象
除了能使用内置的基本对象外,变量表达式还可以使用一些内置的工具对象。
- strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等;
- numbers:数字工具对象,常用的方法有:formatDecimal 等;
- bools:布尔工具对象,常用的方法有:isTrue 和 isFalse 等;
- arrays:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等;
- lists/sets:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等;
- maps:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等;
- dates:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等。
例如,我们可以使用内置工具对象 strings 的 equals 方法,来判断字符串与对象的某个属性是否相等
${#strings.equals('小衰',name)}
选择变量表达式
选择变量表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object 的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代中使用选择变量表达式({…})获取该对象中的属性,其中,“”即代表该对象。
<div th:object="${session.user}" >
<p th:text="*{fisrtName}">firstname</p>
</div>
th:object 用于存储一个临时变量,该变量只在该标签及其后代中有效,在后面的内容“th 属性”
链接表达式
不管是静态资源的引用,还是 form 表单的请求,凡是链接都可以用链接表达式 (@{…})。
链接表达式的形式结构如下:
- 无参请求:@{/xxx}
- 有参请求:@{/xxx(k1=v1,k2=v2)}
例如使用链接表达式引入 css 样式表
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
Thymeleaf公共页面抽取
在一个web项目中,常会有一些公共页面片段(重复代码),们一般会把这些公共页面片段抽取出来,存放在一个独立的页面中,然后再由其他页面根据需要进行引用,这样可以消除代码重复,使页面更加简洁。
抽取公共页面
Thymeleaf 作为一种优雅且高度可维护的模板引擎,同样支持公共页面的抽取和引用。我们可以将公共页面片段抽取出来,存放到一个独立的页面中,并使用 Thymeleaf 提供的 th:fragment 属性为这些抽取出来的公共页面片段命名。
<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
引用公共页面
在 Thymeleaf 中,我们可以使用以下 3 个属性,将公共页面片段引入到当前页面中。
- th:insert:将代码块片段整个插入到使用了 th:insert 属性的 HTML 标签中;
- th:replace:将代码块片段整个替换使用了 th:replace 属性的 HTML 标签中;
- th:include:将代码块片段包含的内容插入到使用了 th:include 属性的 HTML 标签中。
使用上 3 个属性引入页面片段,都可以通过以下 2 种方式实现。
- ~{templatename::selector}:模板名::选择器
- ~{templatename::fragmentname}:模板名::片段名
示例:
在页面 fragment.html 中引入 commons.html 中声明的页面片段
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id"></div>
启动spring boot,使用浏览器访问fragment.html,查看源码
<!--th:insert 片段名引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
<!--th:insert id 选择器引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
<!--th:replace id 选择器引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
------------------------------------------------
<!--th:include 片段名引入-->
<div>
<span>公共页面片段</span>
</div>
<!--th:include id 选择器引入-->
<div>
<span>公共页面片段</span>
</div>
传递参数
传入参数
引用公共页面片段时,我们可以通过以下 2 种方式,将参数传入到被引用的页面片段中:
- 模板名::选择器名或片段名(参数1=参数值1,参数2=参数值2)
- 模板名::选择器名或片段名(参数值1,参数值2)
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name(var1='insert-name',var2='insert-name2')"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id(var1='insert-id',var2='insert-id2')"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name(var1='replace-name',var2='replace-name2')"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id(var1='replace-id',var2='replace-id2')"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name(var1='include-name',var2='include-name2')"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id(var1='include-id',var2='include-id2')"></div>
使用参数
<!--使用 var1 和 var2 声明传入的参数,并在该片段中直接使用这些参数 -->
<div th:fragment="fragment-name(var1,var2)" id="fragment-id">
<p th:text="'参数1:'+${var1} + '-------------------参数2:' + ${var2}">...</p>
</div>
启动 Spring Boot,使用浏览器访问 fragment.html,结果如下图。
Spring boot 整合 Thymeleaf
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
创建模板文件
Spring boot通过ThymeleafAutoConfiguration自动配置类对 Thymeleaf 提供了一整套的自动化配置方案
部分源码
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
public class ThymeleafAutoConfiguration {
}
ThymeleafAutoConfiguration 使用 @EnableConfigurationProperties注解导入ThymeleafProperties类
该类包含了Thymeleaf相关的自动配置
部分源码
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
...
}
ThymeleafProperties 通过 @ConfigurationProperties 注解将配置文件(application.properties/yml) 中前缀为 spring.thymeleaf 的配置和这个类中的属性绑定。
在 ThymeleafProperties 中还提供了以下静态变量:
- DEFAULT_ENCODING:默认编码格式
- DEFAULT_PREFIX:视图解析器的前缀
- DEFAULT_SUFFIX:视图解析器的后缀
示例:
创建页面
创建一个名为 hello.html 的页面,并将该页面放在项目类路径(resources)下的 templates 目录中
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:text 为 Thymeleaf 属性,用于获取指定属性的值-->
<h1 th:text="'小衰'+${name}"></h1>
</body>
</html>
创建控制类
创建HelloController类
@Controller
public class HelloController {
@RequestMapping(value = "/yosoroHello")
public String Yosoro(Map<String,Object> map){
//通过 map 向前台页面传递数据
map.put("name", "Yosoro");
return "hello";
}
}
注意:
在创建控制类的时候最好在启动类同级或者子级的地方创建
Spring boot 推荐starter模块
Spring Boot 推荐的基础 POM 文件
名称 | 说明 |
---|---|
spring-boot-starter | 核心 POM,包含自动配置支持、日志库和对 YAML 配置文件的支持。 |
spring-boot-starter-amqp | 通过 spring-rabbit 支持 AMQP。 |
spring-boot-starter-aop | 包含 spring-aop 和 AspectJ 来支持面向切面编程(AOP)。 |
spring-boot-starter-batch | 支持 Spring Batch,包含 HSQLDB。 |
spring-boot-starter-data-jpa | 包含 spring-data-jpa、spring-orm 和 Hibernate 来支持 JPA。 |
spring-boot-starter-data-mongodb | 包含 spring-data-mongodb 来支持 MongoDB。 |
spring-boot-starter-data-rest | 通过 spring-data-rest-webmvc 支持以 REST 方式暴露 Spring Data 仓库。 |
spring-boot-starter-jdbc | 支持使用 JDBC 访问数据库。 |
spring-boot-starter-security | 包含 spring-security。 |
spring-boot-starter-test | 包含常用的测试所需的依赖,如 JUnit、Hamcrest、Mockito 和 spring-test 等。 |
spring-boot-starter-velocity | 支持使用 Velocity 作为模板引擎。 |
spring-boot-starter-web | 支持 Web 应用开发,包含 Tomcat 和 spring-mvc。 |
spring-boot-starter-websocket | 支持使用 Tomcat 开发 WebSocket 应用。 |
spring-boot-starter-ws | 支持 Spring Web Services。 |
spring-boot-starter-actuator | 添加适用于生产环境的功能,如性能指标和监测等功能。 |
spring-boot-starter-remote-shell | 添加远程 SSH 支持。 |
spring-boot-starter-jetty | 使用 Jetty 而不是默认的 Tomcat 作为应用服务器。 |
spring-boot-starter-log4j | 添加 Log4j 的支持。 |
spring-boot-starter-logging | 使用 Spring Boot 默认的日志框架 Logback。 |
spring-boot-starter-tomcat | 使用 Spring Boot 默认的 Tomcat 作为应用服务器。 |
Spring boot接口
RESTful API接口
什么是REST
Representational State Transfer,翻译是“表现层状态转化”。可以总结为一句话:REST 是所有 Web 应用都应该遵守的架构设计指导原则。
什么是RESTful API
符合 REST 设计标准的 API,即 RESTful API。REST 架构设计,遵循的各项标准和准则,就是 HTTP 协议的表现,换句话说,HTTP 协议就是属于 REST 架构的设计模式。比如,无状态,请求-响应。
参考文献:https://pdai.tech/
为啥要统一封装接口
现在大多数项目采用前后分离的模式进行开发,统一返回方便前端进行开发和封装,以及出现时给出响应编码和信息
以查询某个用户接口而言,如果没有封装, 返回结果如下
{
"userId": 1,
"userName": "小衰"
}
如果封装了,返回正常的结果如下:
{
"timestamp": 11111111111,
"status": 200,
"message": "success",
"data": {
"userId": 1,
"userName": "小衰"
}
}
异常返回结果如下:
{
"timestamp": 11111111111,
"status": 10001,
"message": "User not exist",
"data": null
}
实现案例
状态码的封装
这里以常见的状态码为例,包含responseCode 和 description两个属性。
如果还有其它业务状态码,也可以放到这个类中。
@Getter
@AllArgsConstructor
public enum ResponseStatus {
SUCCESS("200", "success"),
FAIL("500", "failed"),
HTTP_STATUS_200("200", "ok"),
HTTP_STATUS_400("400", "request error"),
HTTP_STATUS_401("401", "no authentication"),
HTTP_STATUS_403("403", "no authorities"),
HTTP_STATUS_500("500", "server error");
public static final List<ResponseStatus> HTTP_STATUS_ALL = Collections.unmodifiableList(
Arrays.asList(HTTP_STATUS_200, HTTP_STATUS_400, HTTP_STATUS_401, HTTP_STATUS_403, HTTP_STATUS_500
));
/**
* response code
*/
private final String responseCode;
/**
* description.
*/
private final String description;
}
返回内容的封装
包含公共的接口返回时间,状态status, 消息message, 以及数据data。
考虑到数据的序列化(比如在网络上传输),这里data有时候还会extends Serializable。
@Data
@Builder
public class ResponseResult<T> {
/**
* response timestamp.
*/
private long timestamp;
/**
* response code, 200 -> OK.
*/
private String status;
/**
* response message.
*/
private String message;
/**
* response data.
*/
private T data;
/**
* response success result wrapper.
*
* @param <T> type of data class
* @return response result
*/
public static <T> ResponseResult<T> success() {
return success(null);
}
/**
* response success result wrapper.
*
* @param data response data
* @param <T> type of data class
* @return response result
*/
public static <T> ResponseResult<T> success(T data) {
return ResponseResult.<T>builder().data(data)
.message(ResponseStatus.SUCCESS.getDescription())
.status(ResponseStatus.SUCCESS.getResponseCode())
.timestamp(System.currentTimeMillis())
.build();
}
/**
* response error result wrapper.
*
* @param message error message
* @param <T> type of data class
* @return response result
*/
public static <T extends Serializable> ResponseResult<T> fail(String message) {
return fail(null, message);
}
/**
* response error result wrapper.
*
* @param data response data
* @param message error message
* @param <T> type of data class
* @return response result
*/
public static <T> ResponseResult<T> fail(T data, String message) {
return ResponseResult.<T>builder().data(data)
.message(message)
.status(ResponseStatus.FAIL.getResponseCode())
.timestamp(System.currentTimeMillis())
.build();
}
}
接口返回时调用
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
/**
* @param user user param
* @return user
*/
@ApiOperation("Add/Edit User")
@PostMapping("add")
public ResponseResult<User> add(User user) {
if (user.getId()==null || !userService.exists(user.getId())) {
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
} else {
user.setUpdateTime(LocalDateTime.now());
userService.update(user);
}
return ResponseResult.success(userService.find(user.getId()));
}
/**
* @return user list
*/
@ApiOperation("Query User One")
@GetMapping("edit/{userId}")
public ResponseResult<User> edit(@PathVariable("userId") Long userId) {
return ResponseResult.success(userService.find(userId));
}
}
感谢参考文献
http://c.biancheng.net/
https://pdai.tech/
seCode())
.timestamp(System.currentTimeMillis())
.build();
}
}
#### 接口返回时调用
```java
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
/**
* @param user user param
* @return user
*/
@ApiOperation("Add/Edit User")
@PostMapping("add")
public ResponseResult<User> add(User user) {
if (user.getId()==null || !userService.exists(user.getId())) {
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
} else {
user.setUpdateTime(LocalDateTime.now());
userService.update(user);
}
return ResponseResult.success(userService.find(user.getId()));
}
/**
* @return user list
*/
@ApiOperation("Query User One")
@GetMapping("edit/{userId}")
public ResponseResult<User> edit(@PathVariable("userId") Long userId) {
return ResponseResult.success(userService.find(userId));
}
}
感谢参考文献
http://c.biancheng.net/
https://pdai.tech/