SpringBootWeb应用实战

编程

1 介绍

        SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。

SpringBoot所具备的特征有:

(1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;

(2)内嵌Tomcat或Jetty等Servlet容器;

(3)提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;

(4)尽可能自动配置Spring容器;

(5)提供准备好的特性,如指标、健康检查和外部化配置;

(6)绝对没有代码生成,不需要XML配置;

SpringBoot和SpringMvc区别:

Spring 是一个“引擎”;

Spring MVC 是基于Spring的一个 MVC 框架 ;

Spring Boot 是基于Spring的条件注册的一套快速开发整合包。

SpringBoot几个常用的注解:

(1)@RestController和@Controller指定一个类,作为控制器的注解 ,并说明其区别

(2)@RequestMapping方法级别的映射注解,这一个用过Spring MVC的小伙伴相信都很熟悉

(3)@EnableAutoConfiguration和@SpringBootApplication是类级别的注解,根据maven依赖的jar来自动猜测完成正确的spring的对应配置,只要引入了spring-boot-starter-web的依赖,默认会自动配置Spring MVC和tomcat容器

(4)@Configuration类级别的注解,一般这个注解,我们用来标识main方法所在的类,完成元数据bean的初始化。

(5)@ComponentScan类级别的注解,自动扫描加载所有的Spring组件包括Bean注入,一般用在main方法所在的类上

(6)@ImportResource类级别注解,当我们必须使用一个xml的配置时,使用@ImportResource和@Configuration来标识这个文件资源的类。

(7)@Autowired注解,一般结合@ComponentScan注解,来自动注入一个Service或Dao级别的Bean

(8)@Component类级别注解,用来标识一个组件,比如我自定了一个filter,则需要此注解标识之后,Spring Boot才会正确识别。

(9)@Transactional事务注解就行,在方法就是方法事务,类上就是类事务。

2 实战

2.1 项目搭建

创建maven工程,引入依赖

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.2.0.RELEASE</version>

<relativePath></relativePath>

</parent>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependencies>

在resource下创建application.properties文件

#编码设置

server.tomcat.uri-encoding=UTF-8

spring.http.encoding.charset=UTF-8

spring.http.encoding.force=true

spring.http.encoding.enabled=true

spring.messages.encoding=UTF-8

# tomcat config

server.tomcat.accept-count=1000

server.tomcat.max-threads=500

# session超时时间,单位是秒

server.servlet.session.timeout=1800

#当前应用http端口

server.port=8787

#访问地址

#server.servlet.context-path=/spring-boot-web-demo

创建启动类

@SpringBootApplication

public class Application {

private static Logger logger = LoggerFactory.getLogger(Application.class);

public static void main(String[] args) {

SpringApplication application = new SpringApplication(Application.class);

application.run(args);

logger.info("启动成功");

}

}

创建Controller

@RestController

@RequestMapping("/api/demo")

public class DemoController {

@RequestMapping(value = "/hello", method = RequestMethod.GET)

public String hello() {

return "hello world";

}

}

运行Application类,后打开浏览器访问

2.2 配置

2.2.1 本地配置

        Spring程序会按优先级从下面这些路径来加载application.yml和application.properties配置文件,同时会先加载application.yml文件再加载application.properties配置文件

(1)当前目录下的/config目录

2)当前目录

3)classpath里的/config目录

4)classpath 跟目录

因此,要外置配置文件就很简单了,在jar所在目录新建config文件夹,然后放入配置文件,或者直接放在配置文件在jar目录

同时可以按Profile不同环境读取不同配置不同环境的配置设置一个配置文件,例如:

  • dev环境下的配置配置在application-dev.properties中
  • test环境下的配置配置在application-test.properties中

在application.properties中指定使用哪一个文件

spring.profiles.active = dev

2.2.2 自定义配置文件

2.2.3 远程配置

        目前比较流行的远程配置有spring官方的spring-clould-config、携程的apollo以及阿里nacos,它们各有千秋。参考链接5,6,7

2.3 Swagger2集成

        现如今,前后端分离已经逐渐成为互联网项目一种标准的开发方式,前端与后端交给不同的人员开发,但是项目开发中的沟通成本也随之升高,这部分沟通成本主要在于前端开发人员与后端开发人员对WebAPI接口的沟通,Swagger2 就可以很好地解决,它可以动态生成Api接口文档,降低沟通成本,促进项目高效开发。

pom.xml添加依赖

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger2</artifactId>

<version>2.9.2</version>

</dependency>

<dependency>

<groupId>io.springfox</groupId>

<artifactId>springfox-swagger-ui</artifactId>

<version>2.9.2</version>

</dependency>

Swagger配置类

@Configuration

@EnableSwagger2

public class SwaggerConfigurer {

@Bean

public Docket createRestApi() {

return new Docket(DocumentationType.SWAGGER_2)

.apiInfo(apiInfo())

.select().apis(RequestHandlerSelectors.basePackage("com.linewell.license"))

.paths(PathSelectors.any())

.build();

}

private ApiInfo apiInfo() {

ApiInfoBuilder builder = new ApiInfoBuilder();

builder.title("spring-boot-demo");

builder.description("spring-boot-demo rest api文档");

builder.version("1.0");

return builder.build();

}

}

在开发中使用相关注解

@Api(tags = {"DEMO相关接口"})

@RestController

@RequestMapping("/api/demo")

public class DemoController {

@ApiOperation("HELLO接口")

@RequestMapping(value = "/hello", method = RequestMethod.GET)

public String hello() {

return "hello world";

}

}

启动项目,打开浏览器查看接口信息

2.4 Mybatis集成

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>1.3.4</version>

</dependency>

<dependency>

<groupId>tk.mybatis</groupId>

<artifactId>mapper-spring-boot-starter</artifactId>

<version>2.1.5</version>

</dependency>

<!--分页插件-->

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper-spring-boot-starter</artifactId>

<version>1.2.10</version>

</dependency>

application.properties添加数据库相关配置

#数据库相关配置

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo

spring.datasource.username=root

spring.datasource.password=123456

#最大连接数

spring.datasource.tomcat.max-active=20

#最大空闲数

spring.datasource.tomcat.max-idle=8

#最小空闲数

spring.datasource.tomcat.min-idle=8

#初始化连接数

spring.datasource.tomcat.initial-size=10

#对池中空闲的连接是否进行验证,验证失败则回收此连接

spring.datasource.tomcat.test-while-idle=true

spring.datasource.tomcat.validation-query=SELECT 1

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# mybatis

mybatis.type-aliases-package=com.spring.boot.demo.model

mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

如果想要看sql日志则需要在logback中配置相应的mapper日志等级为debug

<logger name="com.spring.boot.demo.mapper" level="DEBUG" />

开启事务

2.5 Security集成

SpringBoot和Security高度集成,这里只介绍初级的用法。

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

Security配置

2.6 组件封装

2.6.1 过滤器

方式一

方式二:

2.6.2 拦截器

2.6.3 事件监听器

方式一:

方式二:

在resource路径下新建META-INF/spring.factories文件,SpringBoot在加载的时候会自动加载该配置文件。

2.6.4 定时器

在Application中新增@EnableScheduling注解

定义任务类

@Component

public class CustomTask {

@Scheduled(cron = "0/15 * * * * ? ")

public void taskDemo(){

//任务开始

}

}

2.11 健康检测

SpringBoot自带的监控神器Actuator,集成非常简单,使用起来更是简单到爽歪歪,就是简单地rest接口调用查看,在要求不高的监控环境可以使用

2.11.1 集成

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

在application.properties配置文件新增配置

#监控相关配置

#设置监控访问的应用根路径,默认是/actuator

management.endpoints.web.base-path=/actuator

#暴露监控访问接口,默认是/health和/info

management.endpoints.web.exposure.include=*

#显式屏蔽监控访问接口

#management.endpoints.web.exposure.exclude=env,metrics

#开放关闭应用程序端点,不建议开启

management.endpoint.shutdown.enabled=false

#显示健康详情

management.endpoint.health.show-details=always

启动项目,这里要注意一点是,由于一般监控是不需要登录就能够访问的,所以在security的配置中应该将监控相应的url过滤掉。

启动项目,通过浏览器访问监控相应url

2.11.2自定义应用信息

在application.properties添加以下配置

#应用基本信息

info.app.name=spring boot demo

info.company.name=www.linewell.com

info.build.artifactId=$project.artifactId$

info.build.version=$project.version$

info.build.time=$project.build.time$

在浏览器中访问

2.11.3自定义检测端点

actuator自带了一些检测端点,如mysql等,但是有时候项目需要自定义一些检测端点,但是又想使用actuator故需要自定义检测端点。

@Component

public class CustomHealthIndicator extends AbstractHealthIndicator {

@Override

protected void doHealthCheck(Health.Builder builder) throws Exception {

builder.status(Status.UP);

builder.withDetail("message" ,"custom health indicator");

}

}

在浏览器中访问

2.12 单元测试

SpringBoot的单元测试很简单,只需在pom.xml添加以下依赖即可

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

2.12.1 Service层测

@RunWith(SpringRunner.class)

@SpringBootTest

public class UserServiceTest {

@Autowired

private UserDao userDao;

@Test

public void getUser(){

User user = userDao.getUserByUserName("admin");

System.out.println(user.getUserName());

}

}

2.12.2 Controller层测试

@RunWith(SpringRunner.class)

@SpringBootTest

public class MenuControllerTest {

@Autowired

private WebApplicationContext wac;

@Autowired

private UserDao userDao;

private MockMvc mvc;

private MockHttpSession session;

@Before

public void setupMockMvc(){

//初始化MockMvc对象

mvc = MockMvcBuilders.webAppContextSetup(wac).build();

session = new MockHttpSession();

User user = userDao.getUserByUserName("admin");

//拦截器那边会判断用户是否登录,所以这里注入一个用户

session.setAttribute("LOGIN-INFO",user);

}

@Test

public void getMenus() throws Exception{

mvc.perform(MockMvcRequestBuilders.get(AipVersionConstant.API + AipVersionConstant.API_VERSION_01 + "/menu")

.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)

.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)

.session(session))

.andExpect(MockMvcResultMatchers.status().isOk())

.andDo(MockMvcResultHandlers.print());

}

}

1.mockMvc.perform执行一个请求

2.MockMvcRequestBuilders.get(“/user/1”)构造一个请求,Post请求就用.post方法

3.contentType(MediaType.APPLICATION_JSON_UTF8)代表发送端发送的数据格式是application/json;charset=UTF-8

4.accept(MediaType.APPLICATION_JSON_UTF8)代表客户端希望接受的数据类型为application/json;charset=UTF-8

5.session(session)注入一个session,这样拦截器才可以通过

6.ResultActions.andExpect添加执行完成后的断言

7.ResultActions.andExpect(MockMvcResultMatchers.status().isOk())方法看请求的状态响应码是否为200如果不是则抛异常,测试不通过

8.andExpect(MockMvcResultMatchers.jsonPath(“$.author”).value(“嘟嘟MD独立博客”))这里jsonPath用来获取author字段比对是否为嘟嘟MD独立博客,不是就测试不通过

9.ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息

2.13 静态资源

SpringBoot默认的静态文件路径是在resource/static文件夹下,如果想改变静态资源路径可以在application.properties中新增或修改以下配置,多个路径用逗号隔开。

#静态资源路径

spring.resources.static-locations= classpath:./static

2.14打包

SpringBoot由于内置了Tomcat或者Jetty所以SpringBoot推荐使用jar包的方式进行打包,但是也支持War包的方式进行打包,看各个项目的自己的需求。

2.14.1 .jar方式打包

jar方式打包一般会配合maven-assembly-plugin进行打包。

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

<executions>

<execution>

<goals>

<goal>repackage</goal>

</goals>

</execution>

</executions>

<configuration>

<mainClass>com.linewell.license.demo.Application</mainClass>

<layout>ZIP</layout>

<includes>

<!--<include>

<groupId>nothing</groupId>

<artifactId>nothing</artifactId>

</include>-->

<include>

<groupId>com.linewell.license.platform</groupId>

<artifactId>license-platform-common-mybatis-mapper</artifactId>

</include>

<include>

<groupId>com.linewell.license.platform</groupId>

<artifactId>license-platform-common-model</artifactId>

</include>

</includes>

</configuration>

</plugin>

<!-- 将jar包和外部配置等文件整体打包(zip,tar,tar.gz等) -->

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-assembly-plugin</artifactId>

<configuration>

<skipAssembly>${assembly.skip.param}</skipAssembly>

<!--jar包名称 -->

<finalName>${project.artifactId}</finalName>

<descriptors>

<descriptor>package.xml</descriptor>

</descriptors>

</configuration>

<executions>

<execution>

<id>make-assembly</id>

<phase>package</phase>

<goals>

<goal>single</goal>

</goals>

</execution>

</executions>

</plugin>

</plugins>

<resources>

<resource>

<directory>src/main/resources</directory>

<filtering>false</filtering>

<includes>

<include>config/**</include>

<include>mybatis/**</include>

<include>logback-spring.xml</include>

<include>META-INF/spring.factories</include>

<!-- 如果是war打包则可以注释静态资源的包含 -->

<include>static/**</include>

</includes>

</resource>

</resources>

</build>

在跟目录下新建package.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<assembly

xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">

<id>package</id>

<formats>

<format>tar.gz</format>

</formats>

<!-- 改为false不会出现两层相同的目录 -->

<includeBaseDirectory>false</includeBaseDirectory>

<fileSets>

<!-- bin文件 -->

<fileSet>

<directory>src/main/bin</directory>

<outputDirectory>./</outputDirectory>

</fileSet>

<!-- 配置文件 -->

<fileSet>

<directory>target/classes/config</directory>

<outputDirectory>./config</outputDirectory>

<includes>

<include>application.yml</include>

</includes>

</fileSet>

<!-- 前端工程文件 -->

<fileSet>

<directory>/target/classes/static</directory>

<outputDirectory>./static</outputDirectory>

</fileSet>

<!-- 把项目自己编译出来的jar文件,打包进zip文件的根目录 -->

<fileSet>

<directory>${project.build.directory}</directory>

<outputDirectory>${file.separator}</outputDirectory>

<includes>

<include>*.jar</include>

</includes>

</fileSet>

</fileSets>

<dependencySets>

<dependencySet>

<outputDirectory>libs</outputDirectory>

<scope>runtime</scope>

<excludes>

<exclude>com.linewell.license:*</exclude>

<exclude>com.linewell.license.platform:*</exclude>

</excludes>

</dependencySet>

</dependencySets>

</assembly>

2.14.2 .war方式打包

pom.xml中将SpringBoot自带的tomcat依赖去除

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

<!-- 如果打包成war或者使用jetty应该移除SpringBoot内置的tomcat包 -->

<exclusions>

<exclusion>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-tomcat</artifactId>

</exclusion>

</exclusions>

</dependency>

添加war包插件

<plugin>

<artifactId>maven-war-plugin</artifactId>

<configuration>

<!--如果想在没有web.xml文件的情况下构建WAR,请设置为false。-->

<failOnMissingWebXml>false</failOnMissingWebXml>

</configuration>

</plugin>

静态文件

在那个项目新增webapp目录放置静态文件,这样会自动打到war中,这里需要注意一点在WEB-INF下新建web.xml是有效的可以在里面设置过滤或者sessionTime等配置。

3 参考链接

1、https://baike.baidu.com/item/Spring%20Boot/20249767?fr=aladdin

2、https://www.zhihu.com/question/64671972/answer/223383505

3、https://blog.csdn.net/kikock/article/details/81021578

4、https://blog.csdn.net/d124939312/article/details/89711865

5、https://www.jianshu.com/p/2b14544f7773

6、https://www.jianshu.com/p/85d76c878fb0

7、https://nacos.io/zh-cn/docs/what-is-nacos.html

8、https://baijiahao.baidu.com/s?id=1634315317161175683&wfr=spider&for=pc

9、https://www.jianshu.com/p/d59f06724f1b

10、https://www.cnblogs.com/harrychinese/p/springboot_unittesting.html

以上是 SpringBootWeb应用实战 的全部内容, 来源链接: utcz.com/z/513184.html

回到顶部