Spring Boot
版权申明:本课程版权属于和作者,未经允许,不得将该笔记用于商业用途和其他不正当
导读:课程概览
是什么
2002 Spring Java EEJava Enterprise
)开发中真正意义上的标准,但是随着技术的发展,使用逐渐变得笨重起来,大
XML 繁琐的配置,整合第三方框架的配置问题,导致了开发和部署效率的
2012 10 Mike Youngstrom Spring jira 在框架中支持
Web 。他谈到了在主容器引导容器内配置容器服务。这是请求的摘录:
Spring Web Spring 置模型的工具和参考体系结构。在简单的 方法引导的容器内嵌入和统一这些常用
容器服务的配置。
2013 Spring Boot Spring Boot 2.0.3 RELEASESpring Boot Spring 是和框架紧密结合用于
Spring
Spring Boot),大部分的应用都只需要非常少量的配置代码(基于的配置),
为什么学习2.1 Spring我们打开的,可以看到下图:我们可以看到图中官方对的定位:,任何东西。旨在尽
Spring 位:SpringCloudCoordinate AnythingSpringCloud Data FlowConnect everything仔细品味一下,官网对、和三者定位的措辞
Spring 相关达人课课程届时也会上线)。
的优点来看
有哪些优点?主要给我们解决了哪些问题呢?我们以下图来说明:良好的基因
是伴随着诞生的,从字面理解,是引导的意思,因此旨在帮
Spring Spring Boot Spring Spring 更加方便快捷。
简化编码
web Spring Spring 文件中添加多个依赖,而则会帮助开发着快速启动一个容器,在Boot pom starter-web 我们点击进入该依赖后可以看到,这个已经包含了多个依赖,包括之前在
工程中需要导入的依赖,我们看一下其中的一部分,如下:
Spring Boot 2.2.3 Spring Java EE“”XMLAnnotationSpring Boot是采用的方式,对进行配置。举个例子:
<groupId></groupId>
spring-boot-starter-web</dependency>
省略其他依赖 <dependency>
org.springframework<artifactId></artifactId>
5.0.7.RELEASE<scope></scope>
<dependency>
org.springframework<artifactId></artifactId>
5.0.7.RELEASE<scope></scope>
我新建一个类,但是我不用 注解,也就是说,它是个普通的类,那么我们如何使它也成为一
Bean Spring @Configuration @Bean @Configuration @Bean BeanTestService 让去管理了,在其他地方,我们如果需要使用该,和原来一样,直接使用
注解注入进来即可使用,非常方便。
Spring xml properties Spring Boot application.yml2.2.4 在使用时,项目部署时需要我们在服务器上部署,然后把项目打成包扔到里,在使用后,我们不需要在服务器上去部署,因为内嵌了
,我们只需要将项目打成包,使用 -一键式启动项目。
JDK2.2.5 我们可以引入依赖,直接使用方式来获取进程的运行期性能参数,
Spring Boot 配套功能,没有外围监控集成方案,没有外围安全管理方案,所以在微服务架构中,还需要Cloud 2.3 微服务是未来发展的趋势,项目会从传统架构慢慢转向微服务架构,因为微服务可以使不同的团队专注
Spring Spring REST API Spring Boot 看出,是未来发展的一个大趋势。
本课程能学到什么
TestService public sayHello return ;
}
orgspringframeworkcontextannotationBeanimport ....;
public class {
public () {
TestService}
@Resource
TestService testService本课程使用目前最新版本,课程文章均为作者在实际项目中剥离出来的场
demo Spring Boot Spring Boot 项目中。全篇分为两部分:基础篇和进阶篇。基础篇(课)主要介绍在项目中最常使用的一些功能点,旨在带领学习者快速掌握
在开发时需要的知识点,能够把相关技术运用到实际项目架构中去。该部分
Spring Boot JsonMVC板引擎、异常处理、处理、持久层集成等等。进阶篇(课)主要是介绍在项目中拔高一些的技术点,包括集成的一些组件,旨在
Spring Boot 主线,内容包括拦截器、监听器、缓存、安全认证、分词插件、消息队列等等。认真读完该系列文章之后,学习者会快速了解并掌握在项目中最常用的技术点,作者课程
Spring Boot 习者可以运用该架构于实际项目中,具备使用进行实际项目开发的能力。课程所有源码提供免费下载:
4. 本课程适合以下人群阅读:
JavaSpringMaven有传统项目经验,想往微服务方向发展的工作人员
Spring Boot 希望了解的研究人员
本课程开发环境和插件
开发工具:JDK JDK 1.8
版本:Maven3.5.2
FastJson
Thymeleaf
Redis
Shiro
6. 导读:课程概览
01Spring Boot第课:返回数据及数据封装
03Spring Bootslf4j课:中的项目属性配置
05Spring BootMVC课:集成展现在线接口文档
07Spring BootThymeleaf课:中的全局异常处理
09Spring BootAOP课:中集成课:事务配置管理
12Spring Boot课:中使用拦截器
14Spring BootRedis
15Spring BootActiveMQ
16Spring BootShiro
17Spring BootLucence
18Spring Boot欢迎关注我的为微信公众号:武哥聊编程
01Spring Boot
SpringBoot jdk Spring Boot的启动、项目工程的结构做一下讲解和分析1. jdk 本课程是使用进行开发,在中配置的方式很简单,打开 -
1. SDKs
在中选择本地的安装目录
在中为自定义名字
jdk STS eclipse 加:
---来添加本地------选择,和保持一致。
工程的构建
快速构建
中可以通过 --来快速构建工程。如下,选择
Project SDK jdk NextGroupcom.itcodai
:填项目名称,本课程中每一课的工程名以 课号 course01
:可以添加我们项目中所需要的依赖信息,根据实际情况来添加,本课程只需要选
Web 2.2 第二种方式可以通过官方构建,步骤如下:
http://start.spring.io/在页面上输入相应的版本、和信息以及项目依赖,然后创建项目。
IDEA maven File>New>Model from Existing Source 择解压后的项目文件夹即可。如果是使用的朋友,可以通过 -Projects>Next 2.3 maven创建了项目之后,需要进行配置。打开 -,搜索,配置一
maven 在中选择本地的安装路径;在中选择本地的配置文件所在路径。在配置文件中,我们配置一下国内阿里的镜像,这样在下载依赖时,速
如果是使用的朋友,可以通过 ------来配置,配置
2.4 同样地,新建项目后,我们一般都需要配置编码,这点非常重要,很多初学者都会忘记这一步,所以要
IDEA File>settings encoding<mirror>
nexus-aliyun<mirrorOf></mirrorOf>
Nexus aliyun<url></url>
如果是使用的朋友,有两个地方需要设置一下编码:
,将改成window-->perferences-->General-->content typesTextDefault encodingutf-8
,编码设置完成即可启动项目工程了。
项目工程结构
项目总共有三个模块,如下图所示:
路径:主要编写业务程序
路径:存放静态文件和配置文件
路径:主要编写测试程序
Course01Application@SpringBootApplication main Spring Boot main Spring Boot tomcattomcat到此为止,就启动成功了,为了比较清楚的看到效果,我们写一个来测试一
重新运行方法启动项目,在浏览器中输入 ,如果看到
,那么恭喜你项目启动成功!就是这么简
8080 application.yml server.port 为指定端口,如端口:
总结
IDEA jdk IDEA maven 建和启动工程。对的支持非常友好,建议大家使用进行Boot Spring Boot 课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
02Spring BootJson
Json Spring Boot 返回格式的数据很简单,在中使用 注解即可返回格式的数
@RestController Spring Boot 西。
comitcodaicourse01controllerimport .....;
orgspringframeworkwebbindannotationRestController@RestController
()
StartController @RequestMapping"/springboot"public startSpringBootreturn ;
}
port: 8001
({.})
(.)
@Controller
public @interface {
valuedefault }@RestController @Controller @ResponseBody Spring @Controller @ResponseBody 的数据结构转换为格式。所以在默认情况下,使用了 注解即可将返回的数据
Json Spring Boot Json jackson pom.xml
springbootstarterweb springbootstarterjson Spring Boot springbootstarterxxx 的特点之一,不需要人为去引入很多相关的依赖了,系列直接都包含了所必
springbootstarterjson 到此为止,我们知道了中默认使用的解析框架是。下面我们看一下默认的
框架对常用数据类型的转处理。
默认对的处理
ListMap jackson 对这三个常用的数据结构转成后的格式如何。
创建实体类
User <dependency>
org.springframework.boot<artifactId></artifactId>
2.0.3.RELEASE<scope></scope>
<dependency>
com.fasterxml.jackson.core<artifactId></artifactId>
2.9.6<scope></scope>
<dependency>
com.fasterxml.jackson.datatype<artifactId></artifactId>
2.9.6<scope></scope>
<dependency>
com.fasterxml.jackson.datatype<artifactId></artifactId>
2.9.6<scope></scope>
<dependency>
com.fasterxml.jackson.module<artifactId></artifactId>
2.9.6<scope></scope>
1.2 Controller然后我们创建一个,分别返回 对象、
测试不同数据类型返回的OK User List Map Map value 在浏览器中输入: 返回如下:
User private idprivate usernameprivate password/* getset*/
import ....;
orgspringframeworkwebbindannotationRequestMappingimport .....;
javautilArrayListimport ..;
javautilListimport ..;
@RequestMapping"/json"public class {
()
User getUserreturn new (, ""123456"}
()
ListUsergetUserListListUseruserList new <>User user1 new (, ""123456"User user2 new (, ""123456"userListadduser1userListadduser2return ;
@RequestMapping"/map"public <, > () {
<, > = HashMap();
= User1"""123456"mapput""usermapput"""http://blog.itcodai.com"mapput"CSDN"""mapput""4153return ;
}localhost:8080/json/list json 在浏览器中输入: 返回如下:
map json 1.4 jackson null在实际项目中,我们难免会遇到一些值出现,我们转时,是不希望有这些出现的,比如
null json "" Spring Boot 下配置即可,新建一个的配置类:
"id"1"username""""password""123456"[{:,:""password""123456""id"2"username"""password""123456"{""id"1"username""""password""123456""CSDN""""4153""http://blog.itcodai.com"import ....;
comfasterxmljacksondatabindJsonSerializerimport ....;
comfasterxmljacksondatabindSerializerProviderimport
.....;
orgspringframeworkcontextannotationBeanimport ....;
orgspringframeworkcontextannotationPrimaryimport .....;
javaioIOException@Configuration
JacksonConfig @Bean
@ConditionalOnMissingBeanObjectMapperclasspublic ()
ObjectMapper objectMapper buildercreateXmlMapperfalsebuildobjectMappergetSerializerProvidersetNullValueSerializernew
<>@Override
void (oJsonGenerator jsonGeneratorSerializerProvider serializerProviderthrows {
.(}
return ;
}fastJson
上手难易程度
中等
中等
官方文档、支持
英文
json略快
然后我们修改一下上面返回的接口,将几个值改成测试一下:
localhost:8080/json/map jackson null 字符串了。
使用阿里巴巴的设置
的对比
fastJson json 就是阿里的,那么和有哪些区别呢?根据网上公开的资料比较得到下表。
fastJson jackson 的框架。从扩展上来看,没有灵活,从速度或者上手难度来看,可以考虑,
fastJson2.2 fastJson使用需要导入依赖,本课程使用版本,依赖如下:
使用处理@RequestMapping"/map"public <, > () {
<, > = HashMap();
= User1""nullmapput""usermapput"""http://blog.itcodai.com"mapput"CSDN"nullmapput""4153return ;
{""id"1"username""""password""""CSDN""""4153"""http://blog.itcodai.com"<dependency>
com.alibaba<artifactId></artifactId>
1.2.35</dependency> fastJson null jackson 类,然后覆盖 方法,在方法中,我们可以选择对要实现转换的
3. import ....;
comalibabafastjsonsupportconfigFastJsonConfigimport .....;
orgspringframeworkcontextannotationConfigurationimport ...;
orgspringframeworkhttpconverterHttpMessageConverterimport
......;
javaniocharsetCharsetimport ..;
javautilList@Configuration
fastJsonConfig WebMvcConfigurationSupport /**
使用阿里 作为* @param converters
@Override
void (<<?>>
) {
= FastJsonHttpMessageConverterFastJsonConfig config new ();
.(
保留空的字段
.,
将类型的转成
.,
将类型的转成SerializerFeatureWriteNullNumberAsZero// Listnull[]
.,
将类型的转成SerializerFeatureWriteNullBooleanAsFalse// SerializerFeatureDisableCircularReferenceDetectconvertersetFastJsonConfigconfigconvertersetDefaultCharsetCharsetforName"UTF-8"ListMediaTypemediaTypeList new <>// Controller@RequestMappingproduces
mediaTypeListaddMediaTypeAPPLICATION_JSONconvertersetSupportedMediaTypesmediaTypeListconvertersaddconverter}
以上是返回的几个代表的例子,但是在实际项目中,除了要封装数据之外,我们往
json code msg 样调用者可以根据或者做一些逻辑判断。所以在实际项目中,我们需要封装一个统一的
返回结构存储返回信息。
定义统一的结构
json json json
般来说,应该有默认的返回结构,也应该有用户指定的返回结构。如下:
JsonResultT{
T dataprivate codeprivate msg/**
若没有数据返回,默认状态码为,提示信息为:操作成功!
public () {
.= ;
.= "}
* * @param code
*/
JsonResultString , msgthiscode codethismsg msg}
* 0* @param data
public () {
.= ;
.= ;
.= "}
* 0* @param data
*/
JsonResultT dataString ) {
.= ;
.= ;
.= ;
// getset}修改中的返回值类型及测试
JsonResult 换成具体的数据类型即可,非常方便,也便于维护。在实际项目中,还可以继续封装,比如状态码和提
了)。根据以上的,我们改写一下,如下:
localhost:8080/jsonresult/user json 输入: ,返回如下:
localhost:8080/jsonresult/map json @RestController
()
JsonResultController @RequestMapping"/user"public <> () {
= User1"""123456"return new <>user}
()
JsonResultListgetUserListListUseruserList new <>User user1 new (, ""123456"User user2 new (, ""123456"userListadduser1userListadduser2return new <>userList""}
()
JsonResultMapgetMapMapStringObjectmap new <>3User user new (, "nullmapput""usermapput"""http://blog.itcodai.com"mapput"CSDN"nullmapput""4153return new <>map}
{:,:{:,:,:""msg""功!{:,:[{:,:,:"{:,:,:""msg"""{:,:{""id"1"password""""username""""CSDNnull""4153"""http://blog.itcodai.com""msg"""通过封装,我们不但将数据通过传给前端或者其他接口,还带上了状态码和提示信息,这在实际
4. 本节主要对中数据的返回做了详细的分析,从默认的框架到
fastJson 项目中使用的封装结构体,加入了状态码和提示信息,使得返回的数据信息更加完整。
戳我下载
课:使用进行日志记录
System.out.println() System.out slf4j logback 的,提供了一套日志系统,是最优的选择。
介绍
SLF4JSimple Logging Facade for Java服务于各种各样的日志系统。按照官方的说法,是一个用于日志系统的简单,允许
这段的大概意思是:你只需要按统一的方式写记录日志的代码,而无需关心日志是通过哪个日志系统,
slf4j 志,并且绑定了(即导入相应的依赖),则日志会以的风格输出;后期需要改为以的风格输出日志,只需要将替换成即可,不用修改项目中的代码。这对于第三方组件的
和日志级别的判断。
sflfl4j slf4j Java正式版》中,日志规约一项第一条就强制要求使用
【强制】应用中不可直接使用日志系统(、)中的,而应依赖使用日志框架
中的,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
强制两个字体现出了的优势,所以建议在实际项目中,使用作为自己的日志框架。使用
记录日志非常简单,直接使用创建即可。
中对日志的配置
orgslf4jLoggerimport ..;
Test private static final = .(.);
}对支持的很好,内部已经集成了,一般我们在使用的时候,会对做一下配
application.yml Spring Boot application.properties yml yml 更直观,但是文件对格式要求比较高,比如英文冒号后面必须要有个空格,否则项目估计无法启
properties yml yml我们看一下文件中对日志的配置:
是用来指定项目启动的时候,读取哪个配置文件,这里指定的是日志配置文件是根
logback.xml logback.xml logging.level mapper com.itcodai.course03.dao mapper trace sql 印出来,开发时设置成方便定位问题,在生产环境上,将这个日志级别再设置成级别即可
mapper Spring Boot MyBatis 常用的日志级别按照从高到低依次为:、、、
配置文件解析
application.yml logback.xml logback.xml 主要用来做日志的相关配置。在 中,我们可以定义日志输出的格式、路径、控制台输出
3.1 我们来看一下这个定义的含义:首先定义一个格式,命名为,该格式中 表示日
%thread %5level 5%logger{36}表示
36%msg %n 然后再定义一下名为文件路径,日志都会存储在该路径下。 表示第个文件,当日志
i 设置,下面会讲解。这里需要注意的是,不管是系统还是系统,日志存储的路径必须
3.2 logging:
level:
<configuration>
name"LOG_PATTERN" =
<property =value"D:/logs/course03/demo.%d{yyyy-MM-
</configuration><appender> class="ch.qos.logback.core.ConsoleAppender" 配置,定义为。使用上面定义好的输出格式()来输出,使用 引用进
3.3 使用 定义一个名为的文件配置,主要是配置日志文件保存的时间、单个日志文件
3.4 有了上面那些定义后,最后我们使用 来定义一下项目中默认的日志输出级别,这里定义级
INFO INFO <root> 的参数。这样文件中的配置就设置完了。
<appender =class"ch.qos.logback.core.ConsoleAppender"<encoder>
按照上面配置的来打印日志 <pattern></pattern>
</appender>
<configuration>
name"FILE"
=>
class"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"<!-- FILE_PATH-->
${FILE_PATH}<!-- 15-->
15<timeBasedFileNamingAndTriggeringPolicy
=>
单个日志文件的最大,超过则新建日志文件存储 <maxFileSize></maxFileSize>
</rollingPolicy>
<!-- LOG_PATTERN-->
${LOG_PATTERN}</encoder>
</configuration>
<logger =level"INFO" <root =>
ref"CONSOLE" <appender-ref =/>
</configuration>使用在项目中打印日志
Logger log 位符,很方便。
localhost:8080/test/log ======info=====
测试日志级别打印======warn=====
倪升武的个人博客:;倪升武的博客:因为级别比级别高,所以这条没有打印出来,如果将中的日志级别
DEBUGD:\logs\course03\ 大部分都是通过查看日志文件来定位问题。
总结
slf4j Spring Boot slf4j 明,着重分析了 文件中对日志相关信息的配置,包括日志的不同级别。最后针对这些配
Logger 重要的资料。
戳我下载
import ..;
orgslf4jLoggerFactoryimport .....;
orgspringframeworkwebbindannotationRestController@RestController
()
TestController private final static =
.(.);
()
String () {
.(debug===="loggerinfo"======info====="loggererror"=====error===="loggerwarn"======warn====="// String = ;
str2 "blog.csdn.net/eson_15"loggerinfo"======{}CSDN{}"str1str2return ;
}04Spring Boot我们知道,在项目中,很多时候需要用到一些配置的信息,这些信息可能在测试环境和生产环境下会有
写死,最好就是写到配置文件中。比如可以把这些信息写到 文件中。1. 举个例子,在微服务架构中,最常见的就是某个服务需要调用其他服务来获取其提供的相关信息,那么
订单相关的信息,假设 订单服务的端口号是,那我们可以做如下配置:
@Value 的类中加上一个属性,在属性上使用 注解即可获取到配置文件中的配置信息,如下:
注解上通过 即可获取配置文件中和对应的值。我们启动一下项目,在浏览
localhost:8080/test/config 说明我们成功获取到了配置文件中的订单微服务地址,在实际项目中也是这么用的,后面如果因为服务
 
port: 8001
配置微服务的地址
# orderUrl: http://localhost:8002
orgslf4jLoggerimport ..;
orgspringframeworkbeansfactoryannotationValueimport .....;
orgspringframeworkwebbindannotationRestController@RestController
()
ConfigController private static final =
.(.);
()
String ;
()
String () {
.({}"orderUrlreturn ;
}
获取的订单服务地址为:2. 这里再引申一个问题,随着业务复杂度的增加,一个项目中可能会有越来越多的微服务,某个模块可能
调用这些微服务的代码中,如果这样一个个去使用 注解引入相应的微服务地址的话,太过于繁
所以,在实际项目中,业务繁琐,逻辑复杂的情况下,需要考虑封装一个或多个配置类。举个例子:假
户和购物车相关信息,然后对这些信息做一定的逻辑处理。那么在配置文件中,我们需要将这些微服务
也许实际业务中,远远不止这三个微服务,甚至十几个都有可能。对于这种情况,我们可以先定义一个
类来专门保存微服务的,如下:
@ConfigurationProperties prefifix 然后该类中的属性名就是配置中去掉前缀后的名字,一一对应即可。即:前缀名属性名就是配置文件
key@Component SpringSpring 需要注意的是,使用 注解需要导入它的依赖:
,到此为止,我们将配置写好了,接下来写个来测试一下。此时,不需要在代码中一个
url @Resource 方便。如下:
配置多个微服务的地址
# orderUrl: http://localhost:8002
用户微服务的地址
# shoppingUrl: http://localhost:8004
@ConfigurationPropertiesprefix "url"public class {
String ;
String ;
String ;
省去和方法
<dependency>
org.springframework.boot<artifactId></artifactId>
true</dependency>
@RequestMapping"/test"再次启动项目,请求一下可以看到,控制台打印出如下信息,说明配置文件生效,同时正确获取配置文
3. 我们知道,在实际项目中,一般有两个环境:开发环境和生产环境。开发环境中的配置和生产环境中的
到生产环境后,又要将配置信息全部修改成生产环境上的配置,这样太麻烦,也不科学。
发环境的配置,当我们将项目部署到服务器上之后,再指定去读取生产环境的配置。
applicationdev.yml applicationpro.yml 生产环境进行相关配置。这里为了方便,我们分别设置两个访问端口号,开发环境用,生产环境
8002.
application.yml applicationndev.yml public class {
Logger LOGGER LoggerFactorygetLoggerTestControllerclass@Resource
MicroServiceUrl microServiceUrl@RequestMapping"/config"public testConfigLOGGERinfo"====={}"microServiceUrlgetOrderUrlLOGGERinfo"====={}"microServiceUrlgetUserUrlLOGGERinfo"====={}"microServiceUrlgetShoppingUrlreturn ;
}
获取的订单服务地址为:=====http://localhost:8002
获取的用户服务地址为:=====http://localhost:8004
开发环境配置文件
port: 8001
开发环境配置文件
port: 8002 -文件,访问的时候使用端口,部署
application.yml applicationpro.yml 8002 4. 本节课主要讲解了中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微
是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇
署时,诸多配置信息的修改。
戳我下载
课:中的支持
支持主要来介绍实际项目中最常用的几个注解,包括
以及 。主要介绍这几个注解
 
@RestController Spring Boot 可以看出, 注解包含了原来的 注解,使用过
的朋友对 注解已经非常了解了,这里不再赘述, 注解是将返回
Json @RestController @Controller @ResponseBody @RestController @Controller Thymeleaf@RestController json 后解析;但如果不是前后端分离,需要使用模板来渲染的话,一般中都会返回到具体的页
@RestController spring:
active:
@TargetElementTypeTYPE@RetentionRetentionPolicyRUNTIME@Documented
@ResponseBody
RestController String () ""} user.html @RestController user 的,所以这时候我们需要使用 注解。这在下一节集成模板引
2. @RequestMapping
是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。在类
法都是以该地址作为父路径;在方法的级别表示进一步指定到处理方法的映射关系。
6valuemethod producesvalue value method GETPUTPOSTDELETE GET
属性:指定返回内容类型,如@RequestMapping 这个很简单,启动项目在浏览器中输入 测试一下即可。
@RequestMapping method 来指定,上面的方式请求可以直接使用 注解,效果一样。相应地,方式、方式和方式对应的注解分别为
@PathVariable url Spring Boot restfull url GET
id id @PathVariable 这里需要注意一个问题,如果想要中占位符中的值直接赋值到参数中,需要保证中的参
@PathVariable value public getUserreturn ;
@RestController
(= , = )
TestController @RequestMappingvalue "/get"method RequestMethodGETpublic testGetreturn ;
}
()
String (Integer ) {
..(id" idreturn ;
对于访问的,占位符的位置可以在任何位置,不一定非要在最后,比如这样也
/xxx/{id}/user url 一个参数是一样的,例如:
localhost:8080/test/user/2/zhangsan 息:
url value 4. @RequestParam
注解顾名思义,也是获取请求参数的,上面我们介绍了 注解也是获
@RequestParam @PathVariable @PathValiable url urlhttp://localhost:8080/user/{id} @RequestParam request 风格的 url id 码:
id url 要使用属性来说明,比如为: @RequestMapping"/user/{idd}"public testPathVariable@PathVariablevalue "idd"Integer ) {
..(id" idreturn ;
@GetMapping"/user/{idd}/{name}"public testPathVariable@PathVariablevalue "idd"Integer ,
String ) {
..(id" idSystemoutprintln"name" namereturn ;
获取到的为:获取到的为:@GetMapping"/user"public testRequestParam@RequestParam idSystemoutprintln"id" idreturn ;
@RequestMapping"/user"public testRequestParam@RequestParamvalue "idd"required falseInteger ) {
..(id" idreturn ;
除了属性外,还有个两个属性比较常用:
属性:表示该参数必须要传,否则就会报错误,表示可有可无。
属性:默认值,表示如果请求中没有同名参数时的默认值。
url @RequestParam GET url 该注解还可以用于请求,接收前端表单提交的参数,假如前端通过表单提交
两个参数,那我们可以使用 来接收,用法和上面一样。
()
String (String , String
) {
..(username" usernameSystemoutprintln"password" passwordreturn ;
我们使用来模拟一下表单提交,测试一下接口:
@RequestParam 表单中的参数名一致即可。
User private usernameprivate password// set get
使用实体接收的话,我们不能在前面加 注解了,直接使用即可。 postman 一般都是封装一个实体类来接收表单数据,因为实际项目中表单数据一般都很多。
@RequestBody json 来两个参数,此时我们需要在后端封装一个实体来接收。在传递的参数比较多
@RequestBody 我们使用工具来测试一下效果,打开,然后输入请求地址和参数,参数我们用来模拟,如下图所有,调用之后返回
@PostMapping"/form2"public testFormUser userSystemoutprintln"username" usergetUsernameSystemoutprintln"password" usergetPasswordreturn ;
public class {
String ;
String ;
}
()
String (User userSystemoutprintln"username" usergetUsernameSystemoutprintln"password" usergetPasswordreturn ;
可以看出, 注解用于请求上,接收实体参数。它和上面我们介绍的表单提
json 景和需要使用对应的注解即可。
总结
Spring Boot MVC @RestController @RequestMapping @PathVariable @RequestParam @RequestBody 由于 中集成了 所以对返回的注解不再赘述。以上四个注解
课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
06Spring Boot Swagger2 在线接口文档
简介
解决的问题
端技术和后端技术在各自的道路上越走越远。前端和后端的唯一联系,变成了接口,所以文档
那么问题来了,随着代码的不断更新,开发人员在开发新的接口或者更新旧的接口后,由于开发任务的
Swagger 来说,开发人员不需要给他们提供文档,只要告诉他们一个地址,即可展示在线的接口
可以利用在线接口文档测试接口数据,这给开发人员提供了便利。
官方
Swagger ,官方对的定义为:
翻译成中文是:最好的是使用工具构建的。由此可见,官方对其功能和所处
获取到的为:倪升武
password123456 Spring Boot Swagger2 Swagger 2.2.2 Swagger2 2. Swagger2 maven 使用工具,必须要导入依赖,当前官方最高版本是,我尝试了一下,个人感觉
们实际项目中使用的是版本,该版本稳定,界面友好,所以本节课主要围绕着版本来展
3. Swagger2 使用需要进行配置,中对的配置非常方便,新建一个配置类,
的配置类上除了添加必要的 注解外,还需要添加
<dependency>
io.springfox<artifactId></artifactId>
2.2.2</dependency>
<groupId></groupId>
springfox-swagger-ui<version></version>
import ....;
orgspringframeworkcontextannotationConfigurationimport ...;
springfoxdocumentationbuildersPathSelectorsimport ...;
springfoxdocumentationserviceApiInfoimport ...;
springfoxdocumentationspringwebpluginsDocketimport ....;
* @author shengwu ni@Configuration
public class {
public () {
DocketDocumentationTypeSWAGGER_2// apiapiInfo()
apiInfoapiInfo.()
指定要生成接口的包路径,这里把作为包路径,生成中的所有接口
apisRequestHandlerSelectorsbasePackage"com.itcodai.course06.controller".(.())
build}
* api* @return
private () {
ApiInfoBuilder// .(Swagger2"// .(Spring Boot06"// .(" "CSDN"// .()
构建
build}
在该配置类中,已经使用注释详细解释了每个方法的作用了,在此不再赘述。到此为止,我们已经配置
Swagger2 localhost:8080/swaggerui.html swagger2 Swagger2
结合该图,对照上面的配置文件中的配置,可以很明确的知道配置类中每个方法的作用。这
Swagger2 Swagger2 【友情提示】可能有很多朋友在配置的时候会遇到下面的情况,而且还关不掉的,这是因为
4. Swagger2 上面我们已经配置好了,并且也启动测试了一下,功能正常,下面我们开始使用
,主要来介绍中的几个常用的注解,分别在实体类上、类上以及
中的方法上,最后我们看一下是如何在页面上呈现在线接口文档的,并且结合
中的方法在接口中测试一下数据。
实体类注解
User Swagger2 @ApiModel @ApiModelProperty 解,同时为后面的测试做准备。
@ApiModel @ApiModelProperty @ApiModel @ApiModelProperty model 该注解在在线文档中的具体效果在下文说明。
类中相关注解
TestController Controller Swagger2 import ...;
ioswaggerannotationsApiModelProperty@ApiModelvalue ""public class {
(= "private id@ApiModelPropertyvalue ""private username@ApiModelPropertyvalue ""private password// setget}
comitcodaicourse06entiyJsonResultimport ....;
ioswaggerannotationsApiimport ...;
ioswaggerannotationsApiParamimport .....;
orgspringframeworkwebbindannotationPathVariableimport .....;
orgspringframeworkwebbindannotationRestController@RestController
()
(= "public class {
()
(= "public <> ((= 标识Long ) {
模拟数据库中根据获取信息
= Userid"""123456"return new ();
}
@Api @ApiOperation @ApiParam @Api swagger @ApiOperation http @ApiParam 这里返回的是,是第课中学习返回数据时封装的实体。以上是中最常用的
个注解,接下来运行一下项目工程,在浏览器中输入 -看一下
页面的接口状态。
Swagger 经标明,通过页面即可知道该接口的所有信息,那么我们直接在线测试一下该接口返回的信息,输入,看一下返回数据: json 与否,非常方便。上面是对于单个参数的输入,如果输入参数为某个对象这种情况,是什么样
重启项目,在浏览器中输入 -看一下效果:
总结
,本节课详细分析了的优点,以及如何集成,包括配置,相关注
Swagger 处,基本上是每个项目组中必备的工具之一,所以要掌握该工具的使用,也不难。
()
(= "public <> ((= "User user// return new <>}戳我下载
课:集成模板
1. Thymeleaf Thymeleaf Web Java Thymeleaf - HTML
Thymeleaf JSP+JSTL Thymeleaf 板引擎,与传统的不同,可以使用浏览器直接打开,因为可以忽略掉拓展属性,相当于
 
Thymeleaf thymeleaf html html “+” 在浏览器中查看页面效果,当服务启动后,也可以让后台开发人员查看带数据的动态页面效果。比如:
以展示动态数据, 标签是用来动态替换文本的,这会在下文说明。该例子说明浏览器解释
时会忽略中未定义的标签属性(比如 ),所以的模板可以静态地运
Thymeleaf 2. 中使用模板需要引入依赖,可以在创建项目工程时勾选,也可以
另外,在页面上如果要使用模板,需要在页面标签中引入:
相关配置
Thymeleaf Thymeleaf <div =>
class"ui orange basic label" =></div>
<h2 =th:text"${blog.title}"这是静态标题<dependency>
org.springframework.boot<artifactId></artifactId>
<html => update tomcat 4. Thymeleaf 4.1 这个和没啥关系,应该说是通用的,我把它一并写到这里的原因是一般我们做网站的时
404 500 出来。中会自动识别模板目录()下的和文件。我们在
目录下新建一个文件夹,专门放置错误的页面,然后分别打印些信息。以
为例:
controller 404 500 当我们在浏览器中输入 时,故意输入错误,找不到对应
404.html 当我们在浏览器中输入 时,会抛出异常,然后会自动跳
500.html springthymeleafcachefalse 关闭缓存
<html =>
<meta =>
Title</head>
这是页面
</html>
@RequestMapping"/thymeleaf"public class {
()
String () {
"index"}
()
String () {
i 1 0return ;
}Controller @RestController json 用模板引擎时,层就不能用 注解了,因为在使用模板时,返
Controller index.html @RestController index String index.html @Controller 4.2 Thymeleaf 我们来看一下模板中如何处理对象信息,假如我们在做个人博客的时候,需要给前端传博主
然后在层中初始化一下:
Blogger Model blogger.html 染。接下来我们再写一个来渲染信息:
thymeleaf th:object="${}" 种方式来获取对象属性。如下:
th:value="*{}"
th:value="${.}" th:object 使用 .get}" th:object public class {
Long ;
String ;
String ;
省去和}
()
String () {
= Blogger1L"""123456"modeladdAttribute"blogger"bloggerreturn ;
<!DOCTYPE html>
xmlns:th"http://www.thymeleaf.org"<html =>
<meta =>
博主信息</head>
<form ==>
<input =th:value"${blogger.id}"用户姓名:type"text" =th:value"${blogger.getName()}"
登陆密码:type"text" =th:value"*{pass}" </form>
</html> Thymeleaf java localhost:8080/thymeleaf/getBlogger 4.3 Thymeleaf List
List thymeleaf Controller List接下来我们写一个来获取该信息,然后在中遍历这个。如下:
Thymeleaf th:each ${} model 传过来的参数,然后自定义中取出来的每个对象,这里定义为。表单里面可以直接使用
对象属性名来获取中对象的属性值,也可以使用 对象方法来获取,这点和上面处理
*{} thymeleaf
其他常用操作
thymeleaf @GetMapping"/getList"public getListModel modelBlogger blogger1 new (, ""123456"Blogger blogger2 new (, ""123456"ListBloggerlist new <>listaddblogger1listaddblogger2modeladdAttribute"list"listreturn ;
<!DOCTYPE html>
xmlns:th"http://www.thymeleaf.org"<html =>
<meta =>
博主信息</head>
<form ==>
<input =th:value"${blogger.id}"用户姓名:type"text" =th:value"${blogger.name}"登录密码:type"text" =th:value"${blogger.getPass()}"</form>
</html>功能
th:value
<input th:value="${blog.name}" />
设置样式
th:style="'display:'+@{(${sitrue}?'none':'inlineblock')} +
 
点击事件
th:onclick="'getInfo()'"
条件判断
th:href
<a th:href="@{/blogger/login}">Login</a> />
条件判断和
相反
null}>Login</a>
配合 <div th:switch="${user.role}">
配合 <p th:case="'admin'">administator</p>
地址引入
th:action
<form th:action="@{/blogger/update}">
还有很多其他用法,这里就不总结了,具体的可以参考的v3.0。主
Spring Boot thymeleaf5. Thymeleaf Spring Boot thymeleaf Spring Boot thymeleaf 等。最后列举了一些中常用的标签,在实际项目中多使用,多查阅就能熟练掌握,
中的一些标签或者方法不用死记硬背,用到什么去查阅什么,关键是要会在
课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
08Spring Boot在项目开发过程中,不管是对底层数据库的操作过程,还是业务层的处理过程,还是控制层的处理过
那系统的代码耦合度会变得很高,此外,开发工作量也会加大而且不好统一,这也增加了代码的维护成
针对这种实际情况,我们需要将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过
对异常进行处理,对错误信息进行封装,然后返回一个友好的信息给用户。这节主要总结一下项目中如
Spring Boot 1. json 前端或者其他服务请求本服务的接口时,该接口需要返回对应的数据,一般该服务只需要返回请
codemsg 局异常处理信息,因为异常处理信息中一般我们需要把状态码和异常内容反馈给调用方。 json 第课:返回数据及数据封装 json
code msg2. 新建一个全局异常处理类,然后加上 注解即可拦截项
我们点开 注解可以看到, 注解包含了
Spring Boot Spring basePackages 目工程中的所有异常。 注解是为了异常处理完之后给调用方输出一个格式的封装
在项目中如何使用呢?中很简单,在方法上通过 注解来指定具体的
json 几个例子来说明如何来使用。
处理参数缺失异常
JsonResult /**
异常码
protected code/**
异常信息
protected msgpublic () {
.= ;
.= "}
JsonResultString , msgthiscode codethismsg msg}
}
@ResponseBody
GlobalExceptionHandler // log
Logger logger LoggerFactorygetLoggerGlobalExceptionHandlerclass// ……
在前后端分离的架构中,前端请求后台的接口都是通过风格来调用,有时候,比如请求 需
调用时,也可能出现这种情况,此时我们需要定义一个处理参数缺失异常的方法,来给前端或者调用方
 
HttpMessageNotReadableException 处理,如下:
* * @param ex HttpMessageNotReadableException
*/
(.)
(= .)
JsonResult (
) {
.({}"exgetMessagereturn new (, "}
Controller POST @RestController
()
ExceptionController private static final =
.(.);
()
JsonResult test@RequestParam"name"String ,
() passloggerinfo"name{}"nameloggerinfo"pass{}"passreturn new ();
}
Postman 异常被捕获之后,就会进入我们写好的逻辑,给调用方返回一个友好信息,如下:处理空指针异常
先来聊一聊一些注意的地方,比如在微服务中,经常会调用其他服务获取数据,这个数据主要是格式的,但是在解析的过程中,可能会有空出现,所以我们在获取某个时,再通过该
去获取相关信息时,应该要先做非空判断。
多条记录封装在一个中,我们接下来都要去处理数据,那么就有可能出现空指针异常,因为谁也不
对空指针异常的处理很简单,和上面的逻辑一样,将异常信息换掉即可。如下:
@ResponseBody
GlobalExceptionHandler private static final =
.(.);
* * @param ex NullPointerException
*/
(.)
(= .)
JsonResult handleTypeMismatchExceptionNullPointerException exloggererror"{}"exgetMessagereturn new (, "}
这个我就不测试了,代码中有个 方法,模拟了一个
url 2.3 当然了,异常很多,比如还有,数据库还有一些查询或者操作异常等等。由于
异常是父类,所有异常都会继承该异常,所以我们可以直接拦截异常,一劳永
但是项目中,我们一般都会比较详细的去拦截一些常见异常,拦截虽然可以一劳永逸,但是
Exception GlobalExceptionHandler Exception 友好。
拦截自定义异常
务中,服务之间的相互调用很平凡,很常见。要处理一个服务的调用时,那么可能会调用失败或者调用
GlobalExceptionHandler 捕获。
定义异常信息
管理,我们一般会定义一个异常信息枚举类。比如:
"code""500""msg"""@ControllerAdvice
public class {
Logger logger LoggerFactorygetLoggerGlobalExceptionHandlerclass/**
系统异常 预期以外异常
* @return
@ExceptionHandlerExceptionclass@ResponseStatusvalue HttpStatusINTERNAL_SERVER_ERRORpublic () {
.("exreturn new (, "}
/**
业务异常提示信息枚举类
*/
BusinessMsgEnum /** */
(, !"3.2 然后我们可以定义一个业务异常,当出现业务异常时,我们就抛这个自定义的业务异常即可。比如我们
BusinessErrorException 在构造方法中,传入我们上面自定义的异常枚举类,所以在项目中,如果有新的异常信息需要添加,我
/** */
(, "/** */
(, 50!"/** 500 : */
(, "// /**
消息码
private code/**
消息内容
private msgprivate (codeString ) {
.= ;
.= ;
// set get}
* * @author shengwu ni
public class extends {
long = -;
* */
String ;
* */
String ;
BusinessErrorExceptionBusinessMsgEnum businessMsgEnumthiscode businessMsgEnumcodethismessage businessMsgEnummsg}
方法
在业务代码中,我们可以直接模拟一下抛出业务异常,测试一下:
json 4. 本节课程主要讲解了的全局异常处理,包括异常信息的封装、异常信息的捕获和处理,以
基本上每个项目中都需要做全局异常处理。
戳我下载
@ControllerAdvice
public class {
Logger logger LoggerFactorygetLoggerGlobalExceptionHandlerclass/**
拦截业务异常,返回业务异常信息
* @return
@ExceptionHandlerBusinessErrorExceptionclass@ResponseStatusvalue HttpStatusINTERNAL_SERVER_ERRORpublic () {
code exgetCodeString = .();
JsonResultcodemessage}
@RestController
()
ExceptionController private static final =
.(.);
()
JsonResult testExceptiontry int = / ;
catch Exception ethrow new
(.);
return new ();
}
"code""500""msg"""课:中的切面处理
什么是AOPAspect Oriented Programming 关注点。什么是关注点呢?就是关注点,就是你要做的事情。假如你是一位公子哥,没啥人生目标,每
问题,你在玩之前,你还需要起床、穿衣服、穿鞋子、叠被子、做早饭等等等等,但是这些事情你不想
 
A B C 你叠好被子,仆人帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之
 
AOPAOP 不想穿衣服,那么你把仆人解雇就是了!也许有一天,出门之前你还想带点钱,那么你再雇一个仆人
专门帮你干取钱的活!这就是。每个人各司其职,灵活组合,达到一种可配置的、可插拔的程序
2. Spring Boot AOP 2.1 AOP 使用,首先需要引入的依赖。
实现切面
中使用非常简单,假如我们要在项目中打印一些,在引入了上面的依赖之后,我
LogAspectHandler@Aspect @Aspect @Component 交给来管理。
1.@Pointcut2.@Before3.@After4.@AfterReturning5.@AfterThrowing2.2.1 @Pointcut <dependency>
org.springframework.boot<artifactId></artifactId>
@Aspect
public class {
@Pointcut 连接点关注的内容,使得我们可以控制通知什么时候执行。
注解指定一个切面,定义需要拦截的东西,这里介绍两个常用的表达式:一个是使用
,另一个是使用
execution(* com.itcodai.course09.controller..*.*(..))) execution() 第一个 号的位置:表示返回值类型, 表示所有类型
com.itcodai.course09.controller 第二个 号的位置:表示类名, 表示所有类
:这个星号表示方法名, 表示所有的方法,后面括弧里面表示方法的参数,两个句点
annotation() @GetMapping 可以如下定义切面:
@GetMapping 解有不同的逻辑处理,比如 等。所以这种按照注
2.2.2 @Before @Before log 统计,比如获取用户的请求以及用户的地址等等,这个在做个人站点的时候都能用得到,都是常
@Aspect
public class {
* com.itcodai.course09.controller*/
()
void () {}
@Pointcut"@annotation(org.springframework.web.bind.annotation.GetMapping)"public annotationCut@Aspect
public class {
Logger logger LoggerFactorygetLoggerthisgetClass/**
在上面定义的切面方法之前执行该方法
*/
()
void () {对象很有用,可以用它来获取一个签名,然后利用签名可以获取请求的包名、方法名,包括
joinPoint.getArgs() 2.2.3 @After @After @Before注解相对应,指定的方法在切面切入目标方法之后执行,也可以做一些完成
log 到这里,我们来写一个来测试一下执行结果,新建一个如下:
.(===="// Signature signature joinPointgetSignature// String = .();
获取即将执行的方法名
funcName signaturegetNameloggerinfo": {}{}"funcNamedeclaringTypeName// urlip
= ServletRequestAttributesRequestContextHoldergetRequestAttributesHttpServletRequest request attributesgetRequest// url
url requestgetRequestURLtoString// ip
ip requestgetRemoteAddrloggerinfo"url{}ip{}"urlip}
@Aspect
public class {
Logger logger LoggerFactorygetLoggerthisgetClass/**
定义一个切面,拦截包下的所有方法
@Pointcut"execution(* com.itcodai.course09.controller..*.*(..))"public pointCut/**
在上面定义的切面方法之后执行该方法
*/
()
void () {
.(===="Signature signature joinPointgetSignatureString = .();
.({}"method}
启动项目,在浏览器中输入 ,观察一下控制台的输出信息:
log @Before @After 解的实际作用。
注解
注解和 有些类似,区别在于 注解可以用来捕获切入方
需要注意的是:在 注解 中,属性 的值必须要和参数保持一致,否则会
doAfterReturning 值进行增强,可以根据业务需要做相应的封装。我们重启一下服务,再测试一下(多余的我不贴出
@RestController
()
AopController @GetMapping"/{name}"public testAop@PathVariable namereturn + ;
}
方法进入了即将执行方法为,属于
urlhttp://localhost:8080/aop/nameip0:0:0:0:0:0:0:1
方法进入了方法已经执行完
@Component
LogAspectHandler private final = .(.());
* * @param joinPoint joinPoint
*/
(= , = )
void (, resultSignature signature joinPointgetSignatureString = .();
.({}{}"classMethodresult// loggerinfo"{}"result ""}
2.2.5 @AfterThrowing 顾名思义, 注解是当被切方法执行时抛出异常时,会进入 注解的
throwing 一致,否则会报错。该方法中的第二个入参即为抛出的异常。
3. 本节课针对中的切面做了详细的讲解,主要介绍了中的引入,常
api AOP 可以根据具体的业务,做相应的预处理或者增强处理,同时也可以用作异常捕获处理,可以根据具体业
AOP课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
10Spring BootMyBatis
介绍
testAopHello CSDN
Hello CSDN/**
使用处理* @author shengwu ni
*/
@Component
LogAspectHandler private final = .(.());
* * @param joinPoint jointPoint
*/
(= , = )
void (, ) {
= .();
method signaturegetName// loggerinfo"{}{}"methodex}
大家都知道,框架是一个持久层框架,是下的顶级项目。可以让开发者的主
sql Mybatis sql XML Java POJOs 据了半壁江山。本节课程主要通过两种方式来对集成做一讲解。重点讲解一下基
xml 绝对的,有些项目组中可能也在使用的方式)。
的配置
依赖导入
集成,需要导入 ---的依赖,这里我们使
1.3.2我们点开 ---依赖,可以看到我们之前使用时候熟悉的依赖,就
Spring Boot starter 一起,开发者不需要关注繁琐的配置,非常方便。
配置
MyBatis properties.yml <dependency>
org.mybatis.spring.boot<artifactId></artifactId>
1.3.2</dependency>
<groupId></groupId>
mysql-connector-java<scope></scope>
<!-- -->
<groupId></groupId>
mybatis</dependency>
<groupId></groupId>
mybatis-spring</dependency>
服务端口号
port: 8080
数据库地址
url: localhost:3306/blog_test
datasource: # 我们来简单介绍一下上面的这些配置:关于数据库的相关配置,我就不详细的解说了,这点相信大家已
Spring Boot hikari
mapunderscoretocamelcase: true 如数据库中字段名为: , 那么在实体类中可以定义属性为 (甚至可以写成
,也能映射上),会自动匹配到驼峰属性,如果不这样配置的话,针对字段名和属性名不同
3. xml 使用原始的方式,需要新建文件,在上面的配置文件中,我们
xml classpath:mapper/*.xml resources mapper UserMapper.xml 这和整合一样的,中指定的是对应的中指定对应的实体
User户的driver-class-name: com.mysql.jdbc.Driver
useSSL=false=true=utf-
&allowMultiQueries&autoReconnect&failOverReadOnly&maxReconnects
username: root
hikari:
最大连接池数
mybatis:
指定别名设置的包为所有type-aliases-package: com.itcodai.course10.entity
map-underscore-to-camel-case: true # mapper-locations: # mapper- classpath:mapper/*.xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper =>
id"BaseResultMap" =>
column"id" =property"id" <result =jdbcType"VARCHAR" =/>
column"password" =property"password" </resultMap>
id"getUserByName" =parameterType"String"select * from user where user_name = #{username}
</mapper> idusername passwordUserMapper.java 中间省略的代码,我们写一个来测试一下:
http://localhost:8080/getUserByName/CSDN 中用户名为的用户信息(事先搞两个数据进去即可):
Spring Boot Mapper mapper 上面添加 注解即可,但是这种方法有个弊端,当我们有很多个时,那么每一个类上
@Mapper Spring Boot @MaperScan 解,来扫描一个包下的所有。如下:
com.itcodai.course10.dao mapper 4. 基于注解的整合就不需要配置文件了,主要提供了
四个注解。这四个注解是用的非常多的,也很简单,注解后面跟上对应的语句即可,我们
这跟文件中写语句是一样的,这样就不需要文件了,但是有个问题,有人可能会问,如
@Param User (username@RestController
TestController @Resource
UserService userService@RequestMapping"/getUserByName/{name}"public (String ) {
userServicegetUserByNamename}
{:,:,:}
@MapperScan"com.itcodai.course10.dao"public class {
void ([] ) {
.(., );
}
()
getUserLong );@Param sql #{} controller
本上实体类是能和表字段对应上的,最起码也是驼峰对应的,由于在上面配置文件中开启了驼峰的配
@Results 来解决。
中的 注解是用来指定每一个属性和字段的对应关系,这样的话就可以解决上面说
 
xml xml UserMapper.xml@ResultMap @Results @ResultMap UserMapper.xml <resultMap> 值:
xml xml 生成工具去生成,也不需要人为手动敲,所以这种使用方式也很常见。
总结
Spring Boot MyBatis xml 讲解,通过实际配置手把手讲解了的使用方式,并针对注解方式,讲解了常见
和注解都在用。
戳我下载
课:事务配置管理
()
getUserByIdAndName@Param"id"Long , () username@Select"select * from user where id = #{id}"@Results@Resultproperty "username"column "user_name"@Resultproperty "password"column "password"})
getUserLong );
()
()
getUserLong );
id"BaseResultMap" =>user_name
1
123456
事务相关
任何一步操作都有可能发生异常,异常则会导致后续的操作无法完成。此时由于业务逻辑并未正确的完
 
发生异常就回退到事务开始未进行操作的状态。这很好理解,转账、购票等等,必须整个事件流程全部
事务管理是框架中最为常用的功能之一,我们在实际应用开发时,基本上在层处
一个表里插数据,相互没有影响,插多少是多少,不能因为某个数据挂了,把之前插的全部回滚)。
事务配置
依赖导入
Spring Boot mysql 导入了依赖后,会自动注入,我们不需要任何其
@Transactional mybatis 说明了,这里还是使用上一节课中的配置即可。2.2 我们首先在数据库表中插入一条数据:
mapperOK Spring Boot service 际中出现的异常,然后观察一下事务有没有回滚,如果数据库中没有新的记录,则说明事务回滚成功。
<groupId></groupId>
mybatis-spring-boot-starter<version></version>
public interface {
(
Integer ();
@Service
UserServiceImpl UserService 我们来测试一下:
postman 据库,并没有增加一条记录,说明事务生效了。事务很简单,我们平时在使用的时候,一般不会有多少
……
常见问题总结
Spring Boot @Transactional 说是这么说,但是在实际项目中,是有很多小坑在等着我们,这些小坑是我们在写代码的时候没有注意
到时候肯定是抓瞎,需要费很大的精力去排查问题。这一小节,我专门针对实际项目中经常出现的,和事务相关的细节做一下总结,希望读者在读完之后,
3.1 ”“ 首先要说的,就是异常并没有被捕获到,导致事务并没有回滚。我们在业务层代码中,也许已经考虑
我们把异常抛出来了,有异常了事务就会回滚,我们来看一个例子:
private ;
@Transactional
void () {
插入用户信息
.();
手动抛出异常
RuntimeException}
@RestController
TestController @Resource
UserService userService@PostMapping"/adduser"public addUser@RequestBody ) Exception if null useruserServiceisertUseruserreturn ;
else return ;
}
@Service
UserServiceImpl UserService 我们看上面这个代码,其实并没有什么问题,手动抛出一个 来模拟实际中操作数据库
码中的接口,通过测试一下,就会发现,仍然是可以插入一条用户数据的。那么问题出在哪呢?因为默认的事务规则是遇到运行异常()和程序
Error RuntimeException SQLException @Transactional rollbackFor @Transactional(rollbackFor
,这样就没有问题了,所以在实际项目中,一定要指定异常。
异常被吃
要么抛出去,让上一层来捕获处理;要么把异常掉,在异常出现的地方给处理掉。就因为有
try...catch ”“ 一下代码:
controller postman 用户数据,说明事务并没有因为抛出异常而回滚。这个细节往往比上面那个坑更难以发现,因为我们的
try...catch 写代码时,一定要多思考,多注意这种细节,尽量避免给自己埋坑。那这种怎么解决呢?直接往上抛,给上一层来处理即可,千万不要在事务中把异常自己掉。
private ;
@Transactional
void () Exception // userMapperinsertUseruser// throw new ("}
@Service
UserServiceImpl UserService @Resource
UserMapper userMapper@Override
(= .)
void () {
{
插入用户信息
.();
手动抛出异常
SQLException""} () {
异常处理逻辑
}
3.3 事务范围这个东西比上面两个坑埋的更深!我之所以把这个也写上,是因为这是我之前在实际项目中遇
demo 写代码时,遇到并发问题,就会注意这个坑了,那么这节课也就有价值了。我来写个
synchronized 的场景,比如一个数据库中,针对某个用户,只有一条记录,下一个插入动作过来,会先判断该数据库
用户信息,不会出现同一数据库中插入了两条相同用户的信息。但是在压测时,就会出现上面的问题,数据库中确实有两条同一用户的信息,分析其原因,在于事务的
 
完了后,事务关闭。但是没有起作用,其实根本原因是因为事务的范围比锁的范围大。
了,事务没结束的话,第二个线程进来时,数据库的状态和第一个线程刚进来是一样的。即由于InnodbSELECT态),线程二事务开始的时候,线程一还没提交完成,导致读取的数据还没更新。第二个线程也做了插
 
service 的范围比事务的范围大即可。
总结
Spring Boot @Transactional 方便。除此之外,重点总结了三个在实际项目中可能遇到的坑点,这非常有意义,因为事务这东西不出
课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
12Spring Boot@Service
UserServiceImpl UserService @Resource
UserMapper userMapper@Override
(= .)
void () {
实际中的具体业务userMapperinsertUseruser}
1. 什么是监听器?监听器是一种中特殊的类,它们能帮助开发者监听中特定的事
ServletContext, HttpSession, ServletRequest 可以在某些动作前后增加处理,实现监控。
中监听器的使用
监听器的使用场景很多,比如监听上下文用来初始化一些数据、监听用来获
servlet request 我们主要通过这三个实际的使用场景来学习一下中监听器的使用。
监听上下文对象
servlet 用户在点击某个站点的首页时,一般都会展现出首页的一些信息,而这些信息基本上或者大部分时间都
用户量少还可以接受,如果用户量非常大的话,这对数据库也是一笔很大的开销。针对这种首页数据,大部分都不常更新的话,我们完全可以把它们缓存起来,每次用户点击的时候,我
一点,可以再加个定时器,定期的来更新这个首页缓存。就类似与个人博客首页中排名的变化一
下面我们针对这个功能,来写一个,在实际中,读者可以完全套用该代码,来实现自己项目中的
Service然后写一个监听器,实现 接口,重写
方法,将对象传进去。如果我们想在加载或刷新应用
ContextRefreshedEvent 情。如下:
public class {
* * @return
public () {
实际中会根据具体的业务场景,从数据库中查询对应的信息
User1L"""123456"}
/**
使用来初始化一些数据到域中的监听器
* @date 2018/07/05
@Component
MyServletContextListener ApplicationListenerContextRefreshedEvent{ contextRefreshedEvent application application UserService beanbean application 应数据的时候,我们就可以直接从域中获取信息,减少数据库的压力。下面写一个
直接从域中获取信息来测试一下。
http://localhost:8080/listener/user user application 面的课程中我会讲到,到时候再给大家介绍一下的缓存。
监听会话对象
session 都有自己的网站,监听来获取当前在下用户数量是个很常见的使用场景,下面来介绍一下如何
@Override
void ()
// applicationApplicationContext applicationContext contextRefreshedEventgetApplicationContext// service
= .(.);
= .();
获取域对象,将查到的信息放到域中
=
.(.);
.(, );
}
@RequestMapping"/listener"public class {
()
User getUserHttpServletRequest requestServletContext application requestgetServletContextreturn UserapplicationgetAttribute"user"}
/**
使用统计在线用户数的监听器
* @date 2018/07/05
@Component
MyHttpSessionListener HttpSessionListener private static final =
.(.);
* */
Integer = ;
public synchronized sessionCreatedHttpSessionEvent httpSessionEventloggerinfo""count;
.().().(,
);
@Override
void ()
loggerinfo""count;
.().().(,
);
}
HttpSessionListener sessionCreated sessionDestroyed sessionCreated HttpSessionEvent 中的用户数量加方法刚好相反,不再赘述。然后我们写一个
来测试一下。
@RequestMapping"/listener"public class {
* bug
* @return
@GetMapping"/total"public getTotalUserHttpServletRequest requestInteger = IntegerrequestgetSessiongetServletContextgetAttribute"count"return " count}
中是直接获取当前中的用户数量,启动服务器,在浏览器中输入
可以看到返回的结果是,再打开一个浏览器,请求相同的地址可
count 2 2却是。原因是销毁的方法没有执行(可以在后台控制台观察日志打印情况),当重新打开
session session可以将上面的方法改造一下:
()
String (, responseCookie cookie可以看出,该处理逻辑是让服务器记得原来那个,即把原来的记录在浏览器中,下
sessionId 中再次测试一下,即可避免上面的问题。
监听客户端请求对象
ServletRequestListener request
try // sessionIdcookie new (,
.(.().(), ));
.();
设置有效期为天,设置长一点
.( ** );
.();
catch UnsupportedEncodingException eeprintStackTrace}
count ()
.().().();
"" count}
* ServletRequestListener* @author shengwu ni
*/
public class implements {
Logger logger LoggerFactorygetLoggerMyServletRequestListenerclass@Override
void () {
= HttpServletRequestservletRequestEventgetServletRequestloggerinfo"session id{}"requestgetRequestedSessionIdloggerinfo"request url{}"requestgetRequestURLrequestsetAttribute"name"""}
public requestDestroyedServletRequestEvent servletRequestEventloggerinfo"request end"HttpServletRequest request ()
.();
.(name{}"requestgetAttribute"name"}
这个比较简单,不再赘述,接下来写一个测试一下即可。
中自定义事件监听
景:微服务在处理完某个逻辑之后,需要通知微服务去处理另一个逻辑,或者微服务处理完某
B听器来监听,一旦监听到微服务中的某事件发生,就去通知微服务处理对应的逻辑。
自定义事件
ApplicationEvent User User 3.2 接下来,自定义一个监听器来监听上面定义的事件,自定义监听器需要实现
接口即可。如下:
()
String () {
..(name" requestgetAttribute"name"return ;
/**
自定义事件
* @date 2018/07/05
public class extends {
User userpublic (sourceUser usersupersourcethisuser user}
省去、方法
/**
自定义监听器,监听事件
* @date 2018/07/05
@Component
MyEventListener ApplicationListenerMyEvent{
public onApplicationEventMyEvent myEvent// 然后重写 方法,将自定义的事件传进来,因为该事件中,我们定义了
对象(该对象在实际中就是需要处理的数据,在下文来模拟),然后就可以使用该对象的信息
OK场景来触发,针对本文的例子,我写个触发逻辑,如下:
service ApplicationContext ApplicationContext 事件,这样我们自定义的监听器就能监听到,然后处理监听器中写好的业务逻辑。
Controller 在浏览器中输入 ,然后观察一下控制台打印的用户名
4. User user myEventgetUser// Systemoutprintln"" usergetUsernameSystemoutprintln"" usergetPassword}
/**
* @author shengwu ni
@Service
UserService @Resource
ApplicationContext applicationContext/**
发布事件
*/
User getUser2User user new (, ""123456"// MyEvent event new (, );
.();
user}
@GetMapping"/request"public getRequestInfoHttpServletRequest requestSystemoutprintln"requestListenername" requestgetAttribute"name"return ;
本课系统的介绍了监听器原理,以及在中如何使用监听器,列举了监听器的三个常用的案
出具体的代码模型,均能运用到实际项目中去,希望读者认真消化。
戳我下载
课:中使用拦截器
AOP 求。使用场景比较多的是判断用户是否有权限请求后台,更拔高一层的使用场景也有,比如拦截器可以
websocket websocket 资源,的默认静态目录为,该目录下的静态页面、、、图片等等,
1. 使用拦截器很简单,只需要两步即可:定义拦截器和配置拦截器。在配置拦截器中,以后的版本和之前的版本有所不同,我会重点讲解一下这里可能出现的坑。
定义拦截器
HandlerInterceptor HandlerInterceptor 器或者提供的拦截器的鼻祖,所以,首先来了解下该接口。该接口中有三个方法:
方法:该方法的执行时机是,当某个已经匹配到对应的中的某
preHandle(……) 过返回值来决定的,返回则放行,返回则不会向后执行。
方法:该方法的执行时机是,当某个已经匹配到对应的中的某
DispatcherServlet 参数,可以在此做一些修改动作。
方法:顾名思义,该方法是在整个请求处理完成后(包括视图渲染)执
preHandle(……) true
 
/**
自定义拦截器
* @date 2018/08/03
public class implements {
Logger logger LoggerFactorygetLoggerMyInterceptorclass@Override
boolean (, responseObject ) Exception OK1.2 之前,我们都是直接继承类,然后重写
方法来实现拦截器的配置。但是在之后,该方法已经被废弃了
WebMvcConfifigurationSupport 在该配置中重写 方法,将我们上面自定义的拦截器添加进去, 方法是添加要拦截的请求,这里我们拦截所有的请求。这样就配置好拦截器了,接下来写一个
测试一下:
= HandlerMethodhandlerMethod method handlerMethodgetMethodString = .();
.({}===="methodName// truefalsereturn ;
@Override
void (, responseObject , ) Exception loggerinfo"(Controller)}
public afterCompletionHttpServletRequest requestHttpServletResponse
, handlerException exthrows {
.(DispatcherServlet以做一些清理的工作了}
@Configuration
MyInterceptorConfig WebMvcConfigurationSupport @Override
void () {
.(MyInterceptoraddPathPatterns"/**"superaddInterceptorsregistry}
@Controller
()
InterceptorController @RequestMapping"/test"public testreturn ;
} hello.html hello.html hello interceptor 览器中输入 看一下控制台的日志:
1.3 上文中已经介绍了拦截器的定义和配置,但是这样是否就没问题了呢?其实不然,如果使用上面这种配
resources/static/ 片资源或者文件,然后启动项目直接访问,即可看到无法访问的现象。
Spring Boot 2.0 WebMvcConfifigurerAdapterWebMvcConfifigurationSupport 开。
MyInterceptorConfifig addInterceptors 个方法: ,将静态资源放开:
不会止步于此,没错,上面这种方式的确能解决静态资源无法访问的问题,但是,还有更方便的方式来
我们不继承类,直接实现接口,然后重写
方法,将自定义的拦截器添加进去即可,如下:
WebMvcConfifigure Spring Boot ====test====
(Controller)整个请求都处理完咯,也渲染了对应的视图咯,此时我可以做一些清理的工作了
* WebMvcConfigurationSupport直接访问
*/
protected addResourceHandlersResourceHandlerRegistry registryregistryaddResourceHandler"/**"addResourceLocations"classpath:/static/"superaddResourceHandlersregistry}
public class implements {
public addInterceptorsInterceptorRegistry registry// WebMvcConfigurerregistryaddInterceptornew ()).();
}同,继承类的方式可以用在前后端分离的项目中,后台不需要访问静
WebMvcConfifigure 目中,因为需要读取一些图片、文件等等。
拦截器使用实例
判断用户有没有登录
session user user token用户的,如果未登录,则没有该,服务端可以检测这个参数的有无来判断用户有没
preHandle 重启项目,在浏览器中输入 后查看控制台日志,发现被拦截,
localhost:8080/interceptor/test?token=123 2.2 根据上文,如果我要拦截所有 开头的请求的话,需要在拦截器配置中添加这个前缀,但是
/admin /admin/login 要拦截,我就在哪里弄个开关上去,做成这种灵活的可插拔的效果呢?
Controller 不需要拦截掉,即可在该方法上加上我们自定义的注解即可,下面先定义一个注解:
public preHandleHttpServletRequest requestHttpServletResponse
, handlerthrows {
= HandlerMethodhandlerMethod method handlerMethodgetMethodString = .();
.({}===="methodName// token
token requestgetParameter"token"if null token ""equalstokenloggerinfo"……"return ;
// truefalsereturn ;
/**
该注解用来指定某个方法不用拦截
@TargetElementTypeMETHOD@RetentionRetentionPolicyRUNTIMEpublic @interface {
然后在中的某个方法上添加该注解,在拦截器处理方法中添加该注解取消拦截的逻辑,如
Controller http://localhost:8080/interceptor/test2?token=123 不会被拦截。
总结
Spring Boot 都做了详细的分析。之后拦截器的配置支持两种方式,可以根据实际情况选择不同的
用。
戳我下载
课:中集成1. Redis Redis NoSQLNoSQL key-value 据库不一样,不一定遵循传统数据库的一些基本要求,比如说标准,属性,表结构等等,这
NoSQL 可用性等等。
的可以是字符串、哈希、链表、集合和有序集合。类型很多,包括、、
。这些数据类型都支持、、取交集和并集以及更多更丰富的操作,
写入磁盘或者把修改操作写入追加的记录文件中。 有了有哪些好处呢?举个比较简单的例子,看
@Override
boolean (, responseObject ) Exception HandlerMethod handlerMethod () ;
= .();
methodName methodgetNameloggerinfo"===={}===="methodName// // @UnInterception UnInterception unInterception methodgetAnnotationUnInterceptionclassif null unInterceptionreturn ;
// truefalsereturn ;
Redis Mysql redis redis mysql 据,这样网站就不会挂掉。更多关于的介绍以及使用场景,可以谷歌和百度,在这就不赘述了。
安装
vmvare redis centos 7也可以在阿里云中来安装,都可以。只要能的通云主机或者虚拟机的,然后在虚拟机或者
redis redis 安装编译
redisgcc gcc果是自己安装的虚拟机,那么需要先安装一下
redis
https://redis.io centos 种方法是直接使用来下载:
wget解压安装
然后将解压的文件夹放到 下,一般安装软件都放在 下。然后
/usr/local/redis3.2.8/ make 【注】如果失败,可以尝试如下命令:
wget http://download.redis.io/releases/redis-3.2.8.tar.gz
tar –vzxf redis-3.2.8.tar.gz安装成功之后,需要修改一下配置文件,包括允许接入的,允许后台执行,设置密码等等。
redis vi redis.conf
/bind bind n bind 0.0.0.0 redis使用同样的方法,将改成(默认为),允许在后台执行。
requirepass 123456启动目录下,指定刚刚修改好的配置文件来启动
redis 由于我们设置了密码,在启动客户端之后,输入 即可登录进入客户端。
redis 然后来获取如果正常获取到,则说明没有问题。
集成3.1 Spring Boot redis redis starter make MALLOC=libc
bind 0.0.0.0
redis-cli
get name
<groupId></groupId>
spring-boot-starter-data-redis</dependency>
阿里巴巴<dependency>
com.alibaba<artifactId></artifactId>
1.2.35</dependency> fastjson json 存进去。
配置
application.yml redis3.3 api Spring Boot redis api 最常用的供大家学习,其他希望大家自己多学习,多研究。用到会去查即可。
redis RedisTemplate StringRedisTemplate RedisTemplateRedisTemplate json 候,会使用默认的内部序列化器;导致我们存进里面的是乱码之类的东西。当然了,我们可以自
StringRedisTemplate StringRedisTemplate 们提供字符串操作,我们可以将实体类等转成字符串即可,在取出来后,也可以转成相应的对
fastjson 3.3.1 redis:string 新建一个,注入,使用 可以获取 对象,通过该对象即可读写数据库了。如下:
:
: spring#redisredisdatabase5
配置的主机地址,需要修改成自己的
: port6379
: timeout5000
:
:
连接池中的最大空闲连接,默认值也是
: # 0min-idle50
如果赋值为,则表示不限制;如果已经分配了个实例,则此时的状态为耗尽max-active1000
等待可用连接的最大时间,单位毫秒,默认值为,表示永不超时。如果超过等待时间,则直接
JedisConnectionException
: public class {
private ;
* set redis: string* @param key key string json 一下:
redis3.3.2 redis:hash hash string keystringRedisTemplate.opsForHash()
HashOperations<String, Object, Object> 信息都放在下,针对不同用户的订单实体,可以通过用户的来区分,这就相当于两个了。
*/
void (keyString ){
<, > =
.();
.(, );
/**
类型
* @return
public getStringString ){
stringRedisTemplateopsForValuegetkey}
(.)
public class {
Logger logger LoggerFactorygetLoggerCourse14ApplicationTestsclass@Resource
RedisService redisService@Test
void () {
测试的类型
.(,"loggerinfo"{}"redisServicegetString"weichat"// jsonjsonUser user new (, );
.(, .());
.({}"redisServicegetString"userInfo"}
我的微信公众号为:程序员私房菜
{"password":"123456","username":"CSDN"}hash string Spring Boot redis 测试一下:
类型
stringRedisTemplate.opsForList() ListOperations<String, String>
redis 从右侧添加,一个列表最多包含个元素。
public class {
private ;
* set redis: hash* @param key key
* @param value value
public setHashString , filedKeyString ){
<, , > =
.();
.(,, );
/**
类型
* @param filedkey filedkey
*/
String (keyString ){
() .().(, );
}
public class {
Logger logger LoggerFactorygetLoggerCourse14ApplicationTestsclass@Resource
RedisService redisService@Test
void () {
测试的类型
.(, , .());
.({}"redisServicegetHash"user""name"}
@Service api api 自己看文档。其实,这些根据参数和返回值也能知道它们是做什么用的。来测试一下:
总结
RedisService @Resource
StringRedisTemplate stringRedisTemplate/**
类型
* @param value value
*/
long (keyString ){
<, > =
.();
listOperationsleftPushkeyvalue}
* get redis:list* @param key key
* @param end end
*/
ListStringgetListString , startlong ){
stringRedisTemplateopsForListrangekeystartend}
@RunWithSpringRunnerclass@SpringBootTest
Course14ApplicationTests private static final =
.(.);
private ;
public contextLoads//redislistredisServicesetList"list""football"redisServicesetList"list""basketball"ListStringvalList redisServicegetList"list"0-);
(value valListloggerinfo"list{}"value}
} redis Spring Boot redis 目中,通常都用作为缓存,在查询数据库的时候,会先从中查找,如果有信息,则从中取;如果没有,则从数据库中查,并且同步到中,下次中就有了。更新和删除也是如
redisredis 课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
15 Spring BootActiveMQ
介绍
是啥
JMS Java Java Message ServiceJava中间件()的,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
消息服务是一个与具体平台无关的,绝大多数提供商都对提供支持。
只是接口,不同的提供商或者开源组织对其有不同的实现,就是其中之一,它支持
,是推出的。中有几个对象模型:
ConnectionFactory
连接:JMSSession
目的:JMSProducer
消费者:JMS/
JMS JDBC JDBC API JMS 提供同样与厂商无关的访问方法,以访问消息收发服务。本文主要使用
ActiveMQ Apache ActiveMQ JMS1.1J2EE 1.4规范出台已经是很久的事情了,但是在当今的应用中间仍然扮演着特殊的地位。
用在异步消息的处理上,所谓异步消息即消息发送者无需等待消息接收者的处理以及返回,
 
queuetopic主题用于发布订阅式的消息通信。本章节主要来学习一下在中如何使用这两种形式的消
2. ActiveMQ使用首先需要去官网下载,官网地址为:本课程使用的版本是,下载后解压缩会有一个名为的文件夹,没错,这就安装好了,非常简单,开箱即用。打开文件夹会看到里面有个 --
,这个我们是可以加进工程里的,但是使用的话,这个我们不需要。 ActiveMQ bin win32 win64
activemq.bat ActiveMQ消息生产者生产消息发布到中,然后消息消费者从中取出,并且消费消息。这里需要注
queueQueue启动完成后,在浏览器中输入 来访问的服务器,用户名
admin/admin我们可以看到有和这两个选项,这两个选项分别是点对点消息和发布订阅消息的查看
/点对点消息:消息生产者生产消息发布到中,然后消息消费者从中取出,并且消费消
queue 消费的消息。支持存在多个消息消费者,但是对一个消息而言,只会有一个消费者可以消费。
/ topic 息。和点对点方式不同,发布到的消息会被所有订阅者消费。下面分析具体的实现方式。
集成
依赖导入和配置
Spring Boot ActiveMQ starter 然后在配置文件中,对做一下配置:
<groupId></groupId>
spring-boot-starter-activemq</dependency>的创建
Queue Topic ActiveMqConfifig 建,如下:
Queue Topic new ActiveMQQueue new ActiveMQTopic 创建,分别跟上对应消息的名称即可。这样在其他地方就可以直接将这两种消息作为组件注入进来了。
消息的发送接口
Spring Boot JmsMessagingTemplate springactivemq# activemq url
: ::in-memorytrue
:
如果此处设置为,需要添加的依赖包,否则会自动配置失败,无法注入
enabledfalse
* activemq* @author shengwu ni
@Configuration
ActiveMqConfig /**
发布订阅模式队列名称
public static final TOPIC_NAME "activemq.topic"/**
点对点模式队列名称
public static final QUEUE_NAME "activemq.queue"@Bean
Destination topicreturn new ();
@Bean
Destination queuereturn new ();
}
* * @author shengwu ni
@Service
MsgProducer convertAndSend 3.4 3.4.1 消息的生产,我们放到中来做,由于上面已经生成了消息的组件,所以在
中我们直接注入进来即可。然后调用上文的消息发送方法 即可成功生产一条
3.4.2 点对点消息的消费很简单,只要我们指定目的地即可,监听器一直在监听是否有消息过来,如果
@Resource
JmsMessagingTemplate jmsMessagingTemplatepublic sendMessageDestination destinationString ) {
.(, );
}
* ActiveMQ controller
*/
@RequestMapping"/activemq"public class {
Logger logger LoggerFactorygetLoggerActiveMqControllerclass@Resource
MsgProducer producer@Resource
Destination queue@GetMapping"/send/queue"public sendQueueMessageloggerinfo"======"producersendMessagequeue"Queue: hello activemq!"return ;
}
* * @author shengwu ni
@Service
QueueConsumer /**@JmsListener 体的业务需求做相应的逻辑处理即可。
测试一下
http://localhost:8081/activemq/send/queue 日志,出现下面的日志说明消息发送和消费成功。
发布订阅消息的生产和消费
发布订阅消息的生产
topic producer sendMessage 下,不再赘述:
发布订阅消息的消费
/Spring Boot 时点对点消息,所以在使用时,会不起作用,我们需要在配置文件中添加一个
* * @param msg
@JmsListenerdestination ActiveMqConfigQUEUE_NAMEpublic receiveQueueMsgString ) {
..(" msg}
收到的消息为:@RestController
()
ActiveMqController private static final =
.(.);
private ;
private ;
()
String () {
.(==="producersendMessagetopic"Topic: hello activemq!"return ;
}:
:
: 该配置是的话,则为点对点消息,也是默认的。这样是可以解决问题,但是如果这
法。
@JmsListener queue topic containerFactory ActiveMqConfifig /**
的配置
* @author shengwu ni
@Configuration
ActiveMqConfig // /**
注解默认只接收消息如果要接收消息需要设置*/
public (connectionFactoryDefaultJmsListenerContainerFactory factory new
();
.();
相当于在中配置:factorysetPubSubDomaintruereturn ;
}
@JmsListener topic
/**
消息消费者
*/
public class {
* * @param msg
@JmsListenerdestination ActiveMqConfigTOPIC_NAMEcontainerFactory "topicListenerContainer"public receiveTopicMsgString ) {
..(" msg}
指定属性为上面我们自己配置的即可。由于消息可
试。
测试一下
http://localhost:8081/activemq/send/topic 日志,出现下面的日志说明消息发送和消费成功。
总结
jms activemq activemq Spring Boot 点对点消息和发布订阅消息两种方式的配置、消息生产和消费方式。是能力强劲的开源消息
课程源代码下载地址:欢迎关注我的为微信公众号:武哥聊编程
16Spring Boot Shiro
是一个强大、简单易用的安全框架,主要用来更便捷的认证,授权,加密,会话管等等,可
Shiro 1. Shiro Shiro Subject SecurityManager Realm 1. SubjectPrincipals Credentials么。
:身份。可以是用户名,邮件,手机号码等等,用来标识一个登录主体身份;
:凭证。常见有密码,数字证书等等。
Shiro 行身份认证,就需要认证主体。
Topic: hello activemq!
Topic: hello activemq!:安全管理员。这是架构的核心,它就像内部所有原件的保护伞一
SecurityManager Subject 主体上面。我们在与进行交互的时候,实际上是在背后做一些安全操
3. RealmsRealms Shiro 比如用户账户、访问控制等,就会从一个或多个中去查找。我们一般会自己定制
,这在下文会详细说明。
身份和权限认证
身份认证
Shiro Step1Subject.login(token) AuthenticationToken tokenStep2 Subject SecurityManagerShiro作。这里开始真正的认证工作了。
,,:然后就会根据具体的去进行安全认证了。 从图中可以看出,
可以自定义()。
权限认证
是:权限,角色和用户。
permission修改,删除,查看的权利;
role用户():在中,代表访问系统的用户,即上面提到的认证主体。
一个用户可以有多个角色,而不同的角色可以有不同的权限,也可由有相同的权限。比如说现在有三个
12312都可以,而且还可以删除信息,类似于这样。
集成过程
依赖导入
集成需要导入如下依赖:
数据库表数据初始化
demo 用建表,但是为了更加接近实际情况,我们还是加入,来操作数据库。下面是数据库表的脚
<dependency>
org.apache.shiro<artifactId></artifactId>
1.4.0</dependency>
`t_role` (
int11NOT AUTO_INCREMENT COMMENT 主键,
varchar20NULL ''PRIMARY KEY (`id`)
4 CREATE TABLE `id` () NULL ''`username` () NULL ''`password` () NULL ''`role_id` () DEFAULT COMMENT 外键关联,
KEY `role_id` (`role_id`),username
role_id
csdn1
1
csdn2
2
csdn3
3
rolename
admin
teacher
student
permissionname
1
1
student:*
其中,,和,分别存储用户信息,角色信息和权限信息,表建立好了之后,
t_user t_role t_permission 解释一下这里的权限: 表示权限可以是 或者其他, 处表示一个占位符,我们
Shiro 2.2 Realm
realm realm AuthorizingRealm 为该类封装了很多方法,它也是一步步继承自类的,继承了类后,需要重写
doGetAuthenticationInfo() doGetAuthorizationInfo() 具体实现如下,相关的解释我放在代码的注释中,这样更加方便直观:
) ENGINE=InnoDB AUTO_INCREMENT=DEFAULT CHARSET=utf8
`t_permission` (
int11NOT AUTO_INCREMENT COMMENT 主键,
varchar50NOT COMMENT 权限名,
int11NULL 'role'PRIMARY KEY (`id`),
CONSTRAINT `t_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role`
) ENGINE=InnoDB AUTO_INCREMENT=DEFAULT CHARSET=utf8的用户,这时候并没有涉及到密码,也就是说到这一步的时候,即使用户输入的密码不对,也是可以查
authcInfo ShiroShiro它会根据这里面的真实信息与用户前台输入的用户名和密码进行校验, 这个时候也要校验密码了,如果
取与该用户名有关的角色和权限,然后封装到中返回给
配置
realm Shiro realm全管理器过滤器。如下:
* realm
*/
MyRealm AuthorizingRealm @Resource
UserService userService@Override
AuthorizationInfo doGetAuthorizationInfoPrincipalCollection
) {
获取用户名
username () .();
= SimpleAuthorizationInfo// t_roleauthorizationInfosetRolesuserServicegetRolesusername// t_permissionauthorizationInfosetStringPermissionsuserServicegetPermissionsusernamereturn ;
@Override
AuthenticationInfo doGetAuthenticationInfoAuthenticationToken
) AuthenticationException // tokentokenString = StringauthenticationTokengetPrincipal// User user userServicegetByUsernameusernameifuser null// sessionSecurityUtilsgetSubjectgetSessionsetAttribute"user"user// AuthenticationInfo authcInfo new
(.(), .(), );
authcInfo} {
null}
} realm@Configuration
ShiroConfig private static final =
.(.);
* realm
*/
public () {
= MyRealmloggerinfo"====myRealm====="return ;
}
SecurityManager@Configuration
ShiroConfig private static final =
.(.);
* * @return SecurityManager
@Bean
SecurityManager securityManager// realmDefaultWebSecurityManager securityManager new
(());
.(===="return ;
}
SecurityManager realm Shiro realm 配置过滤器:
public class {
Logger logger LoggerFactorygetLoggerShiroConfigclass/**
注入过滤器
安全管理器*/
public () {
定义ShiroFilterFactoryBean shiroFilterFactoryBeannew
();
设置自定义的shiroFilterFactoryBeansetSecurityManagersecurityManager// urlurl
.();
设置成功之后要跳转的链接
.();
设置未授权界面,权限认证失败会访问该shiroFilterFactoryBeansetUnauthorizedUrl"/unauthorized"// LinkedHashMapMapStringStringfilterChainMap new <>// anonfilterChainMapput"/css/**""anon"filterChainMapput"/imgs/**""anon"filterChainMapput"/js/**""anon"filterChainMapput"/swagger-*/**""anon"filterChainMapput"/swagger-ui.html/**""anon"// url filterChainMapput"/login""anon"// “/user/admin” authcfilterChainMapput"/user/admin*""authc"// “/user/student” “admin”filterChainMapput"/user/student*/**""roles[admin]"// “/user/teacher” “user:create”filterChainMapput"/user/teacher*/**""perms[\"user:create\"]"// logoutfilterChainMapput"/logout""logout"// shiroFilterFactoryBeanFilterChainDefinitionMap
.();
.(===="return ;
}
Shiro reaml -> SecurityManager
。在过滤器中,我们需要定义一个,然后将添加进来,结
默认登录的:身份认证失败会访问该认证成功之后要跳转的权限认证失败会访问该需要拦截或者放行的:这些都放在一个中说明
开放权限,可以理解为匿名用户或游客,可以直接访问的
需要身份认证的
注销,执行后会直接跳转到 ; ,即登录页面
参数可写多个,表示是某个或某些角色才能通过,多个参数时写
user"]perms[user]
perms[“user, admin”]从上述代码中可以看出,在中,针对不同的,有不同的权限要求,这里总结一下常用的几个权
2.4 Shiro 到这里,我们对的准备工作都做完了,接下来开始使用进行认证工作。我们首先来设计几
接口一: 使用 来验证身份认证
http://localhost:8080/user/student 接口三: 使用 来验证权限认证
http://localhost:8080/user/login 然后来一下认证的流程:
login.html 录会请求接口四,实现用户登录功能,此时已经保存了用户信息了。
success.html 用户信息。
流程四: 访问接口三,测试权限认证是否成功。
身份、角色、权限认证接口
@RequestMapping"/user"public class {
* * @param request
*/
()
String () {
user requestgetSessiongetAttribute"user"return ;
/**
角色认证测试接口跳转到上文中配置的页面进行展示。
用户登录接口
* @return
@RequestMapping"/student"public studentHttpServletRequest requestreturn ;
/**
权限认证测试接口
* @return
@RequestMapping"/teacher"public teacherHttpServletRequest requestreturn ;
}
@RequestMapping"/user"public class {
* * @param user user
* @return string
@PostMapping"/login"public loginUser userHttpServletRequest request// token
= UsernamePasswordTokenusergetUsernameusergetPassword// subjectSubject subject SecurityUtilsgetSubjecttry// realmsubjectlogintokenrequestgetSessionsetAttribute"user"userreturn ;
catchException eeprintStackTracerequestgetSessionsetAttribute"user"userrequestsetAttribute"error"""return ;
}
我们重点分析一下这个登录接口,首先会根据前端传过来的用户名和密码,创建一个,然后使用
来创建一个认证主体,接下来开始调用 开始进行身份认证了,
token realm doGetAuthenticationInfo token 上文分析的那样,开始进行身份认证。
测试一下
浏览器请求 会进行身份认证,因为此时未登录,所以会跳转
IndexController /login login.html 登录之后,我们在浏览器中请求 接口,会
csdn1 admin请求 接口,会进行权限认证,因为数据库中的用户
user:* user:create 接下来,我们点退出,系统会注销重新让我们登录,我们使用这个用户来登录,重复上述操作,
csdn2 限与配置中的不同,所以认证不通过。
总结
Shiro Spring Boot Shiro 用;然后介绍了的身份认证、角色认证和权限认证;最后结合代码,详细介绍了
Shiro Shiro 会出的整套工作流程。使用的很广泛,希望读者将其掌握,并能运用到实际项目中。
戳我下载
课:中集成1. Lucence Lucene Lucene Apache Lucene
Java Lucene 一个成熟的免费开源工具。就其本身而言,是当前以及最近几年最受欢迎的免费
——1.1 这里提到了全文检索的概念,我们先来分析一下什么是全文检索,理解了全文检索之后,再理解
的原理就非常简单了。何为全文检索?举个例子,比如现在要在一个文件中查找某个字符串,最直接的想法就是从头开始检
OK力了。或者说找包含某个字符串的文件,也是这样,如果在一个拥有几十个的硬盘中找那效率可想而
文章号出现频率出现位置
1[2]
he
1
1[1]
live
2,5,2
2[1]
tom
1
我们得将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对这些有一定
搜索的过程。
建立索引的方式
Lucene 文章的内容为:文章的内容为:首先第一步是将文档传给分词组件(),分词组件会将文档分成一个个单词,并去除标点符
athetoo 元() 。如下:
1[Tom] [lives] [Guangzhou] [I] [live] [Guangzhou]
2[He] [lives] [Shanghai]
Linguistic Processor写,将单词缩减为词根形式,如到等,将单词转变为词根形式,如到等。然后得到词()。如下:
1[tom] [live] [guangzhou] [i] [live] [guangzhou]
2[he] [live] [shanghai]
Indexer以上就是索引结构中最核心的部分。它的关键字是按字符顺序排列的,因此可以用二
Lucene Term Dictionary文件()和位置文件()保存。其中词典文件不仅保存有每个关键词,还保留了
搜索的过程是先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结
Lucene 会比较慢,但是以后就不需要每次都建立索引了,就快了。
Lucene Spring Boot Lucene 2. Spring Boot Lucence
依赖导入
Lucene 最后一个依赖是用来支持中文分词的,因为默认是支持英文的。那个高亮的分词依赖是最后我要做一个
2.2 根据上文的分析,全文检索有两个步骤,先建立索引,再检索。所以为了测试这个过程,我新建两个
类,一个用来建立索引的,另一个用来检索。
建立索引
D:\lucene\data Indexer 先在构造方法中初始化标准分词器和写索引实例。
核心包 <dependency>
org.apache.lucene<artifactId></artifactId>
5.3.1</dependency>
查询解析包 <dependency>
org.apache.lucene<artifactId></artifactId>
5.3.1</dependency>
常规的分词(英文) <dependency>
org.apache.lucene<artifactId></artifactId>
5.3.1</dependency>
支持分词高亮 <dependency>
org.apache.lucene<artifactId></artifactId>
5.3.1</dependency>
支持中文分词 <dependency>
org.apache.lucene<artifactId></artifactId>
5.3.1</dependency>
Indexer /**
写索引实例
private ;
* IndexWriter
* @throws Exception
public (indexDirthrows {
= .(.());
标准分词器,会自动去掉空格啊,等单词
= StandardAnalyzer//IndexWriterConfig config new ();
实例化写索引对象
= IndexWriterdirconfig}
在构造放发中传一个存放索引的文件夹路径,然后构建标准分词器(这是英文的),再使用标准分词器
/**
索引指定目录下的所有文件
* @return
*/
int (dataDirthrows {
获取该路径下的所有文件
[] = FiledataDirlistFilesif null filesfor File file files//indexFileindexFilefile}
//return .();
/**
索引指定的文件
* @throws Exception
private indexFileFile filethrows {
..(" filegetCanonicalPath//getDocumentdocument
= ();
添加到索引中
.();
/**
获取文档,文档里再设置每个字段,就类似于数据库中的一行记录
* @return
*/
Document () Exception Document doc new ();
开始添加字段
添加内容
.(TextField"contents"new ()));
添加文件名,并把这个字段存到索引文件里
.(TextField"fileName"filegetNameFieldStoreYES//docaddnew (, .(),
..));
doc}
main public static mainStringargs//String = ;
需要索引的文件数据存放的目录
dataDir "D:\\lucene\\data"Indexer indexer nullint = ;
记录索引开始时间
startTime SystemcurrentTimeMillistry // indexer new ();
= .();
catch Exception eeprintStackTrace} {
{
(!= ) {
.();
} () {
.();
}
记录索引结束时间
endTime SystemcurrentTimeMillisSystemoutprintln"" (- ) ""Systemoutprintln"" indexedNum ""}
tomcat D:\lucene\data 索引文件的路径:索引文件的路径:索引耗时毫秒
2然后我们去 目录下可以看到一些索引文件,这些文件不能删除,删除了就需要重新构建
####2.2.2 上面把这两个文件的索引建立好了,接下来我们就可以写检索程序了,在这两个文件中查找特定的词。
Searcher public static searchString , qthrows {
获取要查询的路径,也就是索引所在的位置
= .(.());
= .();
构建IndexSearcher searcher new ();
标准分词器,会自动去掉空格啊,等单词
= StandardAnalyzer//QueryParser parser new (, );
通过解析要查询的,获取查询对象,为传进来的待查的字符串
= .();
记录索引开始时间
startTime SystemcurrentTimeMillis//10docsTopDocs docs searchersearchquery10//long = .();
..(" q "" (-) ""Systemoutprintln"" docstotalHits ""//forScoreDoc scoreDoc docsscoreDocs//scoreDoc.docdocID,docIDDocument doc searcherdocscoreDocdoc//fullPath只要我们在建立索引时有定义即可。
..(.());
readerclose}
ok main 一下:
void ([] ) {
indexDir "D:\\lucene"//String = ;
{
(, );
catch Exception eeprintStackTrace}
查一下 这个字符串,执行一下看控制台打印的结果:23 security 我写的很详细,这个代码已经比较全了,可以用在生产环境上。
中文分词检索高亮实战
示,比如我要查某个关键字,查到了之后,将相关的信息点展示出来,并将查询的关键字高亮等等。这
Lucene
2.3.1 我们新建一个类来建立中文索引,建立过程和英文索引一样的,不同的地方在于使用
因为在实际项目中,绝大部分情况是获取到一些文本字符串,然后根据一些关键字去查询相关内容等
匹配共耗时毫秒
1D:\lucene\data\catalina.properties
ChineseIndexer /**
存放索引的位置
private ;
准备一下用来测试的数据
用来标识文档
Integer [] {, , };
String [] {"""""private descs= """海。全市下辖个区,总面积平方公里,年建成区面积平方公里,常住人口万,其
659.1[1-4] “”60002600史和近年的建都史,是中国四大古都之一,有六朝古都、十朝都会之称,是中华文明的重要发祥地,
遗存。南京是国家重要的科教中心,自古以来就是一座崇文重教的城市,有天下文枢、东南第一
”201375211825
16983[8-10] """
/**
生成索引
* @throws Exception
public indexString ) Exception dir FSDirectoryopenPathsgetindexDir// getWriter IndexWriterIndexWriter writer getWriterforint = ; < .; ++Document doc new (); idcitydesc id们获取内容的时候,主要来获取城市描述。南京的描述我故意写的长一点,因为下文检索的时候,根据
然后执行一下方法,将索引保存到 中。
中文分词查询
等需要处理,需要计算出一个得分片段,这是什么意思呢?比如我搜索南京文化跟搜索南京文明
代码和注释:
把上面的数据都生成索引,分别用来标识
.(IntField"id"idsiFieldStoreYESdocaddnew (, [], ..));
.(TextField"desc"descsiFieldStoreYES//writeraddDocumentdoc}
了才真正写到文档中
.();
/**
获取实例
* @throws Exception
private () Exception //SmartChineseAnalyzer analyzer new ();
将中文分词器配到写索引的配置中
= IndexWriterConfiganalyzer//IndexWriter writer new (, );
writer}
void ([] ) Exception new ().();
}
ChineseSearch private static final =
.(.);
ListStringsearchString , qthrows
{
获取要查询的路径,也就是索引所在的位置
= .(.());
= .();
= IndexSearcherreader//每一步的注释我写的很详细,在这就不赘述了。接下来我们来测试一下效果。
测试一下
thymeleaf controller 定索引的目录和需要查询的字符串,如下:
= SmartChineseAnalyzer//QueryParser parser new (, );
通过解析要查询的,获取查询对象
= .();
记录索引开始时间
startTime SystemcurrentTimeMillis//10docsTopDocs docs searchersearchquery10//long = .();
.({}{}"qendTime startTimeloggerinfo"{}"docstotalHits//<b><b/>
= SimpleHTMLFormatter"<b>
"</font></b>"//QueryScorer scorer new ();
根据这个得分计算出一个片段
= SimpleSpanFragmenterscorer//Highlighter highlighter new (, );
设置一下要显示的片段
.();
取出每条查询结果
<> = ArrayList();
(: .) {
相当于根据这个来获取文档
= .(.);
.(, .());
.(, .());
desc docget"desc"//ifdesc nullTokenStream tokenStream analyzertokenStream"desc"new
());
summary highlightergetBestFragmenttokenStreamdescloggerinfo"desc:{}"summarylistaddsummary}
readerclosereturn ;
}@RequestMapping"/lucene"public class {
()
String () {
索引所在的目录
indexDir "D:\\lucene2"// // String q = "";
q ""try ListStringlist ChineseSearchsearchindexDirqmodeladdAttribute"list"list} () {
.();
return ;
}
result.html model <!DOCTYPE html>
lang"en" =>
<meta =>
Title</head>
<div =>
th:utext"${desc}"</div>
</html>
th:test html 启动服务,在浏览器中输入 ,测试一下效果,我们搜索的是
南京文化
controller “”可以看出,不同的关键词,它会计算一个得分片段,也就是说不同的关键字会命中不同位置的内容,然
Lucene 拆分命中,这在实际项目中会很好用。总结
Lucene Spring Boot 成步骤,首先快速带领大家从直观上感受如何建立索引已经如果检索,其次通过中文检索的具
Lucene Lucene 记硬背,拿到项目中根据实际情况做对应的修改即可。
戳我下载
课:搭建实际项目开发中的
前面的课程中,我主要给大家讲解了中常用的一些技术点,这些技术点在实际项目中可能
据实际项目中的需求进行相应的扩展。
进行人为的扩展。这节课我们要做的就是搭建一个最小系统架构。拿着这个架构,可以
从零开始搭建一个环境,主要要考虑几点:统一封装的数据结构、可调式的接口、的处理、模板引
目,所以我在源代码里也加上了)、持久层的集成、拦截器(这个也是可选的)和全局异常
Spring Boot 来扩展了。
Spring Boot
1. 由于封装的数据的类型不确定,所以在定义统一的结构时,我们需要用到泛型。统一的结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加即可,一
/**
统一返回对象
* @param <T>
public class <> private ;
String ;
String ;
* 0*/
JsonResultthiscode "0"thismsg ""大家可以根据自己项目中所需要的一些东西,合理的修改统一结构中的字段信息。
的处理
处理工具很多,比如阿里巴巴的,不过对有些未知类型的无法转成空字符
fastjson 节课里面我们主要集成自带的。主要是对做一下对的配置即可,然
}
* * @param code
*/
JsonResultString , msgthiscode codethismsg msg}
* 0* @param data
public () {
.= ;
.= ;
.= "}
* 0* @param data
*/
JsonResultT dataString ) {
.= ;
.= ;
.= ;
/**
使用自定义异常作为参数传递状态码和提示信息
*/
JsonResultBusinessMsgEnum msgEnumthiscode msgEnumcodethismsg msgEnummsg}
省去和方法
/**
这里先不测试,等下面配置好了之后,我们一起来测试一下。
在线可调式接口
swagger Swagger 示在线的接口文档,除此之外,调用接口的人员还可以在线测试接口数据,同样地,开发人员在开
Swagger swagger * @author shengwu ni
@Configuration
JacksonConfig @Bean
@ConditionalOnMissingBeanObjectMapperclasspublic ()
ObjectMapper objectMapper buildercreateXmlMapperfalsebuildobjectMappergetSerializerProvidersetNullValueSerializernew
<>@Override
void (oJsonGenerator jsonGeneratorSerializerProvider serializerProviderthrows {
.(}
return ;
}
* swagger* @author shengwu ni
@Configuration
public class {
public () {
DocketDocumentationTypeSWAGGER_2// apiapiInfo()
apiInfoapiInfo.()
指定要生成接口的包路径,这里把作为包路径,生成中的所有接口
apisRequestHandlerSelectorsbasePackage"com.itcodai.course18.controller".(.())
build}
* api* @return Controller然后启动项目,在浏览器中输入 -即可看到接口文档页
json 4. 每个项目中是必须要有持久层的,与数据库交互,这里我们主要来集成,集成首先要
application.yml */
ApiInfo apiInforeturn new ()
设置页面标题
title"Spring Boot"// .(Spring Boot18"// .(" ""// .()
构建
build}
@RestController
(= "public class {
private ;
()
(= "public <> ((= 标识Long ) {
= Userid"""123456"return new <>user}
# serverport8080
数据库地址
:
: :springdatasource# driver-class-namecom.mysql.jdbc.Driver dao 使用的方式,甚至两种同时使用都行,这里我们主要使用注解的方式来集成,关于的方式,
关于层我就不在文章中写代码了,大家可以结合我的源代码学习,这一节主要带领大家来搭建
Spring Boot @MapperScan("com.itcodai.course18.dao")
拦截器
url等。除此之外,还需要将常用的静态页面或者页面放行,不能将这些静态资源给拦截了。首
urljdbcmysql//$datasource.url?
8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects
usernameroot
: hikarimaximum-pool-size10 最大连接池数
: mybatis# entity
: configurationmap-underscore-to-camel-casetrue 驼峰命名规范
: 映射文件位置
classpath:mapper/*.xml
UserMapper @Select"select * from user where id = #{id}"@Results@Resultproperty "username"column "user_name"@Resultproperty "password"column "password"})
(id@Select"select * from user where id = #{id} and user_name=#{name}"User getUserByIdAndName@Param"id"Long , () username@Select"select * from user"ListUsergetAll}
MyInterceptor HandlerInterceptor private static final =
.(.);
然后将自定义的拦截器加入到拦截器配置中。
Spring Boot classpath:/static
classpath:/resources
上面代码中配置的 是对所有都进行了拦截,但我们实现了接口,不会导
Spring Boot swagger 以要将其放行。页面在目录下,放行该目录下所有文件即可。
swagger swagger打印的日志判断代码执行的顺序。
全局异常处理
有处理的异常,一般会有一个统一的全局异常处理。在异常处理之前,最好维护一个异常提示信息枚举
public preHandleHttpServletRequest requestHttpServletResponse
, handlerthrows {
.((Controller)"return ;
@Override
void (, responseObject , ) Exception loggerinfo"(Controller)}
public afterCompletionHttpServletRequest requestHttpServletResponse
, handlerException exthrows {
.(DispatcherServlet以做一些清理的工作了}
@Configuration
MyInterceptorConfig WebMvcConfigurer @Override
void () {
实现不会导致静态资源被拦截
.(MyInterceptor// url
addPathPatterns"/**"// swagger
excludePathPatterns"/swagger-resources/**"}
public enum {
参数异常 PARMETER_EXCEPTION"102""!"/** */
(, "/** */
(, 50!"/** 500 : */
(, "/**
消息码
private code/**
消息内容
private msgprivate (codeString ) {
.= ;
.= ;
public codereturn ;
public msgreturn ;
}
常,最后会来一个一劳永逸(异常)。
@ResponseBody
GlobalExceptionHandler private static final =
.(.);
* * @param ex
*/
(.)
(= .)
JsonResult handleBusinessErrorBusinessErrorException exString = .();
message exgetMessagereturn new (, );
其中,是自定义的业务异常,继承一下即可,具体可以看
中有个方法,用来测试全局异常的,打开页面,调用一下
”“根据不同的业务提示不同的信息。
总结
Spring Boot 结构、可调式的接口、的处理、模板引擎的使用(代码中体现)、持久层的集成、拦截器和全局异
Spring Boot 况来扩展了。
戳我下载
附:作者信息
CSDN GitChat 作者:倪升武(武哥)
二维码:
* * @param ex NullPointerException
*/
(.)
(= .)
JsonResult handleTypeMismatchExceptionNullPointerException exloggererror"{}"exgetMessagereturn new (, "}
* * @param ex
*/
(.)
(= .)
JsonResult handleUnexpectedServerException exloggererror""exreturn new (.);
} CSDN 途,否则追究法律责任。
为人:谦逊、激情、博学、审问、慎思、明辨、 笃行
学问:纸上得来终觉浅,绝知此事要躬行
为事:工欲善其事,必先利其器。
转载请标注出处!