springboot-多模块构建-1
1. 场景描述
先介绍下背景,项目为什么需要用多模块?springmvc难道还不够?
(1)设计模式真言:“高内聚、低耦合”,springmvc项目,一般会把项目分成多个包:controller、service、dao、util等,但是随着项目的复杂性提高,想复用其他一个模块的话,因为是包的形式,剥离出来会比较困难,耦合性有点强,常用的方法就是复制代码修改,但是这样会做很多无用功与增加出错几率。
(2)springboot多模块简单来说,就是把按包分模块的模式,借助maven升级到jar的方式,抽象性更加强了,假如jar再升级到到war或者多个集合jar,就成微服务了( springcloud入门系列),在多模块jar模式下可以将某个jar拿出来对外共用,能大大提高代码复用率与开发效率。
2. 解决方案
2.1 整体思路
(1)新建springboot项目;
(2)在新建后的springboot项目中新建多个module;
(3)修改pom文件以及删除多余的文件及文件夹。
2.2 新建springboot项目(springboot项目快速搭建)
(1)new->project
(2)next,名字改一下。
2.3 新建module
(1)在springboot项目上点击右键->new->module
其余方式跟上面的springboot方式一样,不再多说了。
(2)新建三个module:controller、service、dao,新建后的效果图如下:
2.4 删除多余的文件及修改配置文件(重点)
2.4.1 删除多余文件及文件夹
(1)springboot项目
整体删除src文件夹。
(2)module模块
将service和dao下面的application启动类和对应配置文件application.yml/prpperty,一起删除了,cotroller模块的不动。
2.4.2 修改pom.xml
根据springmvc架构,几个module之间依赖顺序 controller->service->dao
(1)修改springboot最外层pom.xml
这个是父pom.xml,用于加载一些全局的或者公共的jar包,以及配置打包。
此pom文件中,需要需改两个地方:
一是修改打包模式为pom;
二是新建modules标签,将3个module增加进来。
如下:
<packaging>pom</packaging>
<modules>
<module>controller</module>
<module>service</module>
<module>dao</module>
</modules>
(2)修改cotroller的pom.xml文件
修改标签为本项目springboot项目的gav信息和依赖service的jar包信息。
<!--<parent>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-parent</artifactId>-->
<!--<version>2.1.6.RELEASE</version>-->
<!--<relativePath/> <!– lookup parent from repository –>-->
<!--</parent>-->
<parent>
<groupId>com.laowang</groupId>
<artifactId>lwmodul</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependency>
<groupId>com.laowang</groupId>
<artifactId>service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
(3)修改service的pom.xml文件
与controller类似,只是依赖改为dao。
<!--<parent>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-parent</artifactId>-->
<!--<version>2.1.6.RELEASE</version>-->
<!--<relativePath/> <!– lookup parent from repository –>-->
<!--</parent>-->
<parent>
<groupId>com.laowang</groupId>
<artifactId>lwmodul</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependency>
<groupId>com.laowang</groupId>
<artifactId>dao</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
(4)修改dao的pom.xml文件
只需修改parent,不需要再配置依赖了。
<!--<parent>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-parent</artifactId>-->
<!--<version>2.1.6.RELEASE</version>-->
<!--<relativePath/> <!– lookup parent from repository –>-->
<!--</parent>-->
<parent>
<groupId>com.laowang</groupId>
<artifactId>lwmodul</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
(5)启动
在Cotroller模块中使用启动类ControllerApplication启动,空项目的话,看到这一行就说明成功了。
Started ControllerApplication in 2.485 seconds (JVM running for 3.639)
2.5 增加web访问验证
2.5.1 配置文件
(1)controller下面的application.property改下端口号(不更改的话默认是:8080)。
server.port=9000
(2)增加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.5.2 启动类
在启动类ControllerApplication增加一个标签(@RestController)和一个请求方法(home())。
package com.laowang.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class ControllerApplication {
public static void main(String[] args) {
SpringApplication.run(ControllerApplication.class, args);
}
@RequestMapping("/")
public String home() {
return "i'm 软件老王,欢迎光临!";
}
}
2.5.3 效果图
springboot不同环境打包
1. 场景描述
springboot+maven打包,项目中经常用到不同的环境下打包不同的配置文件,比如连接的数据库、配置文件、日志文件级别等都不一样。
2. 解决方案
在pom.xml文件中定义
2.1 真实代码
<project>
<dependencies>
</dependencies>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<deploy.type>dev</deploy.type>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<deploy.type>prod</deploy.type>
</properties>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>src/main/profiles/${deploy.type}</directory>
</resource>
<resource>
<directory>src/main/resources/</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2 代码说明
重点是这行代码,结合maven就能打包不同的文件夹。
<resource>
<directory>src/main/profiles/${deploy.type}</directory>
</resource>
2.3 效果图:
2.3.1 程序目录
2.3.2 maven目录
需要打包那个环境的,打钩后双击就可以了。
springboot+druid连接池及监控配置
1. 问题描述
阿里巴巴的数据库连接池Druid在效率与稳定性都很高,被很多开发团队使用,并且自带的Druid监控也很好用,本章简单介绍下springboot+druid配置连接池及监控。
2. 解决方案
2.1 pom.xml
springboot 已经有druid的starter,但是好像有点问题,不知道为什么没拿到jar包,有可能是网络问题,还是使用了原生的druid gav。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.26</version>
</dependency>
<!--starter有点问题,没用-->
<!-- <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>-->
2.2 连接池配置
连接池配置没啥说的,我们当时为了省事,直接将以前项目中的xml导过来了(在application启动上加个标签就好了)
<!-- datasource configuration -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${spring.datasource.maxActive}" />
<property name="initialSize" value="${spring.datasource.initialSize}" />
<property name="maxWait" value="${spring.datasource.maxWait}" />
<property name="minIdle" value="${spring.datasource.minIdle}" />
<property name="timeBetweenEvictionRunsMillis" value="${spring.datasource.timeBetweenEvictionRunsMillis}" />
<property name="minEvictableIdleTimeMillis" value="${spring.datasource.minEvictableIdleTimeMillis}" />
<property name="testWhileIdle" value="${spring.datasource.testWhileIdle}" />
<property name="testOnBorrow" value="${spring.datasource.testOnBorrow}" />
<property name="testOnReturn" value="${spring.datasource.testOnReturn}" />
<property name="poolPreparedStatements" value="${spring.datasource.poolPreparedStatements}" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="${spring.datasource.maxPoolPreparedStatementPerConnectionSize}" />
<property name="filters" value="${spring.datasource.filters}" />
<property name="connectionProperties" value="${spring.datasource.connectionProperties}" />
</bean>
2.3 监控配置
默认继承了一个filter,一个Servlet,使用了两个标签。
2.3.1 filter类
@WebFilter(filterName = "druidWebStatFilter", urlPatterns = "/*",
initParams = {
@WebInitParam(name = "exclusions", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")
}
)
public class DruidStatFilter extends WebStatFilter {
}
2.3.2 servlet类
@WebServlet(urlPatterns = "/druid/*",
initParams = {
@WebInitParam(name = "loginUsername", value = "laowang"),// 用户名
@WebInitParam(name = "loginPassword", value = "lw123"),// 密码
@WebInitParam(name = "resetEnable", value = "false")// 禁用HTML页面上的“Reset All”功能
}
)
public class DruidStatViewServlet extends StatViewServlet {
private static final long serialVersionUID = 1L;
}
2.3.3 启动类上增加标签
@ServletComponentScan
@SpringBootApplication
public class SptestApplication {
public static void main(String[] args) {
SpringApplication.run(SptestApplication.class, args);
}
}
ok,配置完了。
2.4 访问界面
2.4.1 访问首页
地址:http://192.168.0.10:9107/druid/login.html
2.4.2 SQL监控
可以监控具体执行的sql,时间行数等,用于分析慢SQL,优化响应时间。
2.4.3 URI监控
可以看到接口的执行时间及访问次数,为系统优化提供参考。
1. 问题描述
随着软件过程的不断发展,前后端分离开发模式被越来越的开发团队使用,今天介绍下前后分离中必用的接口设计与调试工具-swagger2,前端人员根据swagger的描述,进行参数的传递;前后端联调的时候,出现问题,首先使用swagger进行测试调用,定位问题,还可以通过界面导出swagger2接口文档,修改完善后作为其他系统调用说明文档。
2. 问题方案
采用springboo+swagger2方式运行swagger。
2.1 pom文件配置
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
2.2 springboot启动类配置标签
@EnableSwagger2 //启动swagger注解
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2.3 java代码及swagger界面说明
2.3.1 java代码(针对实际项目做了下处理)
@Api(description = "测试管理类")
public class TestController {
@RequestMapping(value = "/getTestByUid", method = RequestMethod.GET)
@ApiOperation(value = "查询接口,获取当前用户数据", response = Object.class)
public Object getTestByUid(@ApiParam(value = "类型,1公开,2新建,3收藏4,分享") @RequestParam String type) {
try {
Object result = testService.getTestByUid(type);
return new ResponseEntity(result, HttpStatus.OK);
} catch (Exception e) {
logger.error("查询接口报错", e);
return new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
2.3.2 swagger效果图
2.3.3 swagger界面说明
一般使用这几个标签就够用了,详细API说明可以百度一下,就不一一说明了。
(1) @Api(description = "测试管理类")
该标签用于类上,是对整个类的说明,例如:用户管理模块,会在swagger2界面上生成一个一级菜单,方法是它的二级菜单。
(2) @ApiOperation(value = "查询接口,获取当前用户数据", response = Object.class)
该标签用于方法上,Value是描述,还可以定义nodes进行进一步说明。
(3)@ApiParam(value = "类型,1公开,2新建,3收藏4,分享")
改标签用于定义参数描述。
三个标签分别是类->方法->参数
另外:点击 ”Try it out“按钮就可以调用后台服务,进行前后端联调测试及问题定位。
springboot与logback配置
spring boot中无须添加任何依赖,直接在resources文件夹下面新建logback.xml文件,将以下代码复制过去,配置完成,可以使用了。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder 默认配置为PatternLayoutEncoder -->
<encoder>
<pattern>%d [%thread] %msg%n</pattern>
</encoder>
</appender>
<appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<FileNamePattern>log/info-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>180</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<!-- <pattern>%d [%thread] %msg%n</pattern>-->
<pattern> %date %-5level %logger{0} - %message%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="warn_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>log/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>20MB</maxFileSize>
<maxHistory>180</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern> %date %-5level %logger{0} - %message%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>log/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>20MB</maxFileSize>
<maxHistory>180</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern> %date %-5level %logger{0} - %message%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="info_log"/>
<appender-ref ref="warn_log"/>
<appender-ref ref="error_log"/>
</root>
</configuration>
1.2 Linux服务器日志效果图
三个级别info、warn、error文件,根据文件日期和文件大小进行滚动。
2. logback介绍
2.1 背景
人多饭香,logback是log4j创始人重新又搞得一进阶版开源日志系统,号称占用内存小,速度提成10倍以上,测试充分等等,logback配置起来确实简单了不少,但是对于我们大部分程序开发者来说,差异其实也就那样吧,一句话:大家都在用,都说好,用就是了,具体的技术内核,组件组成啥的不详细说了,一般项目用不到,看其他人博客吧。
2.2 logback配置说明
配置说明还是要介绍下,还是很有有必要的。
2.2.1 配置简单秘密
之所以能基本一键配置启动logback,原因在于springboot2.0以上吧,集成了logback,配置依赖已经在starter里面了,只要使用springboot框架,就会自带logbacak 了,只需要在resouces新建一个logback.xml(名字必须是这个)就能直接使用了。
2.2.2 logback配置解析
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="info_log"/>
<appender-ref ref="warn_log"/>
<appender-ref ref="error_log"/>
</root>
配置了拆分成了四个层级分开打印,第一个STDOUT就是到控制台去,其余三个分别为info、warn、error,根据日志和大小进行滚动,拿info进行下说明,其他几个配置基本一样。
<appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>log/info-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>180</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern> %date %-5level %logger{0} - %message%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
重点配置就三个地方
(1) FileNamePattern
定义文件目录及名称命名规则:log/info-%d{yyyy-MM-dd}.%i.log,示例:log/info-2019-06-22.0.log,按天滚动;maxFileSize和maxHistory分别为文件多大滚动和保留多长时间。
(2)layout
定义具体文件排版格式。
2019-06-22 11:09:17,471 INFO LogAspect - [9a90efcc-24b1-4b57-a413-04ed874e29b5] -
(3)filter 过滤日志级别
假如不想区分info、warn、error的话就不用配置多个appender,配置一个,不配置filter就可以了。
RestTemplate真实案例
1. 场景描述
现在越来越的系统之间的交互采用http+json的交互方式,以前用的比较多的HttpClient,后来用的RestTemplate,感觉RestTemplate要比httpClent简洁的多,简单介绍下,项目中正在使用的get和post调用方式。
2. 解决方案
2.1 简要说明
RestTemplate是集成在spring-web中的,因为springboot的starter已经默认加载进来,所以可以直接使用不用再配置maven的gav了。
2.2 post调用方式
2.2.1 真实代码
public static String invoke(String url, HashMap params) throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json; charset=UTF-8"));
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
HttpEntity<String> httpEntity = new HttpEntity<>(JSONObject.toJSONString(params), headers);
RestTemplate rst = new RestTemplate();
ResponseEntity<String> stringResponseEntity = rst.postForEntity(url, httpEntity, String.class);
return stringResponseEntity.getBody();
}
2.2.2 代码说明
invoke是通用方法调用,项目中的入参是:url和map,url是调用地址,写在配置文件中;map是外围系统需要的参数,在相关类中进行封装后传过来。
2.3 get调用方式
2.3.1真实代码
public JSONArray getUsers() throws Exception {
JSONArray result = new JSONArray();
try {
RestTemplate restTemplate = new RestTemplate();
result = restTemplate.getForObject(apiUrl + "/user/list?appCode={1}",
JSONArray.class, code);
} catch (Exception e) {
}
return result;
}
2.3.2 代码说明
其中参数是:url和code,根据code去查询对应集合。
2.4 RestTemplate Api说明
DELETE | delete |
GET | getForObject |
getForEntity | |
HEAD | headForHeaders |
OPTIONS | optionsForAllow |
POST | postForLocation |
postForObject | |
postForEntity | |
PUT | put |
any | exchange |
execute |
一般只需记住get与post的五个就可以了(getForObject 、getForEntity、postForLocation、postForObjec、postForEntity),这几个方法有很多重载的方法,参数不一样,可根据实际情况调用。
springboot+redis实现session共享
1.场景描述
因项目访问压力有点大,需要做负载均衡,但是登录使用的是公司统一提供的单点登录系统,需要做session共享,否则假如在A机器登录成功,在B机器上操作就会存在用户未登录情况。
2. 解决方案
因项目是springboot项目,采用Springboot+Springsession+Redis来实现session共享。
2.1 pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
2.2 springboot中开启session支持
springboot启动类添加@EnableRedisHttpSession标签来开启spring session支持,代码:
@EnableRedisHttpSession
@SpringBootApplication
public class SptestApplication {
public static void main(String[] args) {
SpringApplication.run(SptestApplication.class, args);
}
}
2.3 配置文件中增加配置项
在application.properties中增加配置项
spring.redis.host=10.192.168.13
spring.redis.port=6379
其他还有几个配置项,不影响使用,不详说了,需要了解的可以查看API。