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/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
    <!--</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/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
    <!--</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/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
    <!--</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);
    }
}
LESS 复制 全屏

2.3 配置文件中增加配置项

在application.properties中增加配置项

spring.redis.host=10.192.168.13
spring.redis.port=6379

其他还有几个配置项,不影响使用,不详说了,需要了解的可以查看API。

 

posted @ 2021-03-11 20:54  hanease  阅读(438)  评论(0编辑  收藏  举报