springboot工程环境搭建(idea)
一.后端技术选型
springboot 2.x, yml或properties,内置tomcat
二.项目结构
api-controller,
common - utils ,
mapper - sql ,
generator - mybatis逆向工程,
pojo - 表的实体映射,
service - 服务,
web - 前端页面
三.环境搭建
- 项目聚合(划分子模块)
- springboot集成ssm
- Swagger配合前端
- 日志管理
- 配置全局异常处理
- 配置校验工具
- 访问web前端页面
1.项目聚合
【1】创建父级工程SuperMarket
设置父级工程的打包方式为pom格式
【2】创建子工程common
跟父级工程一样不选择模板,创建SuperMarket-common,
创建子模块后,默认的打开方式为jar包,无需显示指定
创建好工程后,查看父级工程pom中是否存在子模块的配置项
【3】以common的创建方式创建pojo,api,mapper,service
【4】创建web
点击finish,完成工程的创建,打开web的pom,将其他的删除,留下如下就行了
【5】配置子模块间的依赖关系
pojo -> common, 在pojo的pom中添加如下依赖
<!--配置common依赖-->
<dependencies>
<dependency>
<groupId>com.lzy</groupId>
<artifactId>SuperMarket-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
mapper -> pojo, 在mapper的pom中添加如下依赖
<!--配置pojo依赖,pojo和common会自动配置过来-->
<dependencies>
<dependency>
<groupId>com.lzy</groupId>
<artifactId>SuperMarket-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
service -> mapper, 在service的pom中添加如下依赖
<!--配置mapper依赖-->
<dependencies>
<dependency>
<groupId>com.lzy</groupId>
<artifactId>SuperMarket-mapper</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
api -> service ,在api的pom中添加如下依赖
<!--配置service依赖-->
<dependencies>
<dependency>
<groupId>com.lzy</groupId>
<artifactId>SuperMarket-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
web -> api , 在web的pom中添加如下依赖
<!--配置api的依赖-->
<dependencies>
<dependency>
<groupId>com.lzy</groupId>
<artifactId>SuperMarket-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
配置好后,使用父级工程的maven-install将所有模块进行安装安装完成之后模块之间才能相互依赖调用,在顶层项目中,install即可,出现下面信息即为安装成功:
2.springboot的基本配置
【1】在父级pom中添加依赖
<!--配置springboot
引入依赖parent,完成之后就是springboot工程了
作用:加载了很多的依赖
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/>
</parent>
<!--设置资源属性-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<!--引入核心依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!--排除springboot默认的日志依赖-->
<exclusions>
<exclusion>
<groupId>org.springframeork.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<!--排除logback日志-->
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--配置spring自带的web板块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--配置解析xml-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
【2】application.properties
在web的resources下创建
在application.properties中添加配置端口
#配置端口号
#配置服务器端口
server.port=8088
server.tomcat.uri-encoding=utf-8
server.max-http-header-size=80KB
server.servlet.context-path=/
【3】创建启动项application.java
配置如下:
/ / 启动类
@SpringBootApplication // 扫描所有包
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
【4】创建controller测试类
代码:
//controller + ResponseBody
@RestController
public class TestController {
// 指定接收一个get请求
@GetMapping("/test")
public Object test(){
return "success";
}
}
找到父级工程进行install
执行application
测试环境,出现下述内容即为配置成功
【5】springboot与数据源和mybatis配置
<!--配置数据源和mybatis的依赖-->
<!--配置数据源-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<!--配置mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot</artifactId>
<version>2.1.0</version>
</dependency>
在application.properties中配置
#配置数据源
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gues?useUnicode=true&characterEncoding=UTF-8&autoReconnect
spring.datasource.username=root
spring.datasource.password=root
#等待连接池分配连接的最大时长,超过之后不发生连接
spring.datasource.hikari.connection-timeout=30000
#最小连接数
spring.datasource.hikari.minimum-idle=5
#最大连接数
spring.datasource.hikari.maximum-pool-size=20
#自动提交配置
spring.datasource.hikari.auto-commit=true
#连接超时时间
spring.datasource.hikari.idle-timeout=1000000
spring.datasource.hikari.connection-test-query=SELECT 1
#指定pojo类所在包
mybatis.type-aliases-package=com.lzy.pojo
#配置mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
#配置sql打印
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
【6】springboot 配置mybatis的逆向工程
配置xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--数据库驱动-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="false"/>
</commentGenerator>
<!--数据库链接地址账号密码-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/gues" userId="root" password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--生成pojo类存放位置-->
<javaModelGenerator targetPackage="com.lzy.pojo" targetProject="src\main\java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--生成映射文件存放位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src\main\resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!--生成Dao类存放位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.lzy.mapper" targetProject="src\main\java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--生成对应表及类名
example是sql生成语法,设置为false之后,只能手工sql
-->
<table tableName="test" domainObjectName="TestPo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<!-- 使用自增长键 -->
<property name="my.isgen.usekeys" value="true"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
</context>
</generatorConfiguration>
在父级pom中加入mapper的逆向工具
<!--配置mybatis的逆向工具-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
在逆向工程pom中添加
<!--配置mybatis逆向工具-->
<build>
<plugins>
<!--springboot与maven的插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--配置生成mybatis-mapper的文件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<!--配置实现核心-->
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>mybatis.generator</id>
<phase>package</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<!--配置xml详情参数-->
<configuration>
<!--允许移动生成的文件-->
<verbose>true</verbose>
<!--允许自动覆盖文件,项目组中必须设置为false-->
<overwrite>true</overwrite>
<!--配置生成的xml-->
<configurationFile>
<!--找到xml中的路径-->
src/main/resources/mybatis-generator.xml
</configurationFile>
</configuration>
</plugin>
</plugins>
</build>
逆向工程测试
3.Swagger2配置
【1】扫描配置
// 启动类
@SpringBootApplication // 扫描所有包
@MapperScan(basePackages = "com.lzy.mapper")
@ComponentScan(basePackages = {"com.lzy"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
【2】在父级pom中添加依赖
<!--
为了减少程序员撰写文档时间,提高生产力,swagger2应运而生,使用swagger2可以减少编写过多文档,
只要通过代码就能生成文档API,提供前端人员用于测试
-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
在Swagger2中配置
package com.lzy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2 {
// http://localhost:8088/swagger-ui.html 原ui路径
// 配置swagger2核心配置docket
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2) // 指定api的类型为swagger2
.apiInfo(apiInfo()) // 用于定义api文档汇总信息,页面显示的文案材料
.select()
.apis(RequestHandlerSelectors.basePackage("com.lzy.controller")) // 指定controller包
.paths(PathSelectors.any()) // 所有的controller包
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder() // 接口的信息建造者
.title("超市系统平台 接口api") // 文档页标题
.contact(new Contact("lzy",
"https://github.com/longzy-hub/SuperMarket",
"2587234011@qq.com")) // 联系人信息
.description("为贵工程超市系统平台提供的api文档") // 详细信息
.termsOfServiceUrl("https://github.com/longzy-hub/SuperMarket") // 网站地址
.build();
}
}
测试路径:
http://localhost:8088/swagger-ui.html
4.配置日志
【1】移除默认日志
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!--排除springboot默认的日志依赖
后期自己整合-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
【2】在父级pom中添加日志依赖
<!--引入日志依赖 抽象层 与 实现层-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
【3】配置log4j.properties
#设置日志输出的等级为debug,低于debug就不会输出了
#设置日志输出到两种地方,分别叫做 stdout和 file 控制台输出和文件输出
log4j.rootLogger=DEBUG,stdout,file
log4j.additivity.org.apache=true
#第一个地方stdout, 输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.threshold=INFO
#设置输出格式%5p [%t] (%F:%L) - %m%n
#宽度是5的优先等级 线程名称 (文件名:行号) - 信息 回车换行
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-5p %c{1}:%L - %m%n
#以文件形式滚动输出
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.DatePattern='.'yyyy-MM-dd-HH-mm
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file.Threshold=INFO
log4j.appender.file.append=true
log4j.appender.file.File=E:/ideapro/log/SuperMarket/mylog.log
5.配置全局异常处理
【1】CommonReturnType 返回jsondata值
package com.lzy.response;
// 通用返回格式json
public class CommonReturnType {
// 表明对应请求的返回处理结果“success” 和 "fail"
private String status;
// 若status=success,则data内返回前端需要的json数据
// status=fail ,则data内使用通用的错误码格式
private Object data;
public static CommonReturnType create(Object result, String status){
CommonReturnType type = new CommonReturnType();
type.setStatus(status);
type.setData(result);
return type;
}
// 创建一个通用的创建方法
public static CommonReturnType success(Object result){
return CommonReturnType.create(result,"success");
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
【2】CommonError错误类的接口定义
package com.lzy.error;
// 错误类的接口定义
public interface CommonError {
// 错误码
public int getErrCode();
// 错误信息
public String getErrMsg();
// 设置错误信息,返回错误具体子类
public CommonError setErrMsg(String errMsg);
}
【3】EmBusinessError 错误类型枚举
package com.lzy.error;
public enum EmBusinessError implements CommonError {
// 通用错误类型10001
PARAMETER_VALIDATION_ERROR(10001, "参数错误"),
SYSTEM_ERROR(10002,"系统错误"),
UNKNOWN_ERROR(10003, "未知错误")
;
EmBusinessError(int errCode, String errMsg){
this.errCode = errCode;
this.errMsg = errMsg;
}
// 错误码
private int errCode;
// 错误信息
private String errMsg;
@Override
public int getErrCode() {
return this.errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
@Override
public String getErrMsg() {
return this.errMsg;
}
@Override
public CommonError setErrMsg(String errMsg) {
this.errMsg = errMsg;
return this;
}
}
【4】BusinessException 业务异常类
package com.lzy.error;
// 包装器业务异常类实现
public class BusinessException extends RuntimeException implements CommonError {
// 使用构造器注入
private CommonError commonError;
// 直接接收EmBusinessError的传参用于构造业务异常
public BusinessException(CommonError commonError){
super();
this.commonError = commonError;
}
// 接收自定义的errMsg的方法构造业务异常
public BusinessException(CommonError commonError, String errMsg){
super();
this.commonError = commonError;
this.commonError.setErrMsg(errMsg);
}
@Override
public int getErrCode() {
return this.commonError.getErrCode();
}
@Override
public String getErrMsg() {
return this.commonError.getErrMsg();
}
@Override
public CommonError setErrMsg(String errMsg) {
return this.commonError.setErrMsg(errMsg);
}
public CommonError getCommonError() {
return commonError;
}
}
【5】GlobalExceptionHandler 全局异常处理类
package com.lzy.error.handler;
import com.lzy.error.BusinessException;
import com.lzy.error.EmBusinessError;
import com.lzy.response.CommonReturnType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
// 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
// 日志
public static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public CommonReturnType doError(HttpServletRequest httpServletRequest,//
HttpServletResponse httpServletResponse, Exception ex){
ex.printStackTrace();
Map<String, Object> responseData = new HashMap<>();
if (ex instanceof BusinessException){
BusinessException businessException = (BusinessException) ex;
responseData.put("errCode",businessException.getErrCode());
responseData.put("errMsg",businessException.getErrMsg());
}else {
responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
responseData.put("errMsg", EmBusinessError.UNKNOWN_ERROR.getErrMsg());
}
logger.error(responseData.toString());
return CommonReturnType.create(responseData, "fail");
}
}
6.配置校验工具
【1】在父级pom中配合全局异常进行功能整合
<!--校验相关 -->
<!--apache工具包,方便常规操作 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!--hibernate校验工具 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.4.Final</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<!--hutool工具 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.7</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.3.7</version>
<type>pom</type>
</dependency>
【2】ValidationResult:结果返回结构
package com.lzy.validator;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
// 结果返回结构
public class ValidationResult {
// 校验结果是否有错
private boolean hasErrors = false;
// 存储错误信息的map
private Map<String, String> errorMsgMap = new HashMap<>();
public boolean isHasErrors() {
return hasErrors;
}
public void setHasErrors(boolean hasErrors) {
this.hasErrors = hasErrors;
}
public Map<String, String> getErrorMsgMap() {
return errorMsgMap;
}
public void setErrorMsgMap(Map<String, String> errorMsgMap) {
this.errorMsgMap = errorMsgMap;
}
// 实现通用的通过格式化字符串信息获取错误结果的msg方法
public String getErrMsg(){
return StringUtils.join(errorMsgMap.values().toArray(),",");
}
}
【3】ValidatorApi:校验器接口
package com.lzy.validator;
import com.lzy.error.BusinessException;
import org.springframework.beans.factory.InitializingBean;
// 校验器接口api
public interface ValidatorApi extends InitializingBean {
public void check(Object bean) throws BusinessException;
}
【4】ValidatorImpl:校验器
package com.lzy.validator.impl;
import cn.hutool.core.map.MapUtil;
import com.lzy.error.BusinessException;
import com.lzy.error.EmBusinessError;
import com.lzy.validator.ValidationResult;
import com.lzy.validator.ValidatorApi;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
@Component
public class ValidatorImpl implements ValidatorApi {
private Validator validator;
@Override
public void check(Object bean) throws BusinessException {
ValidationResult result = validator(bean);
if (MapUtil.isNotEmpty(result.getErrorMsgMap())){
if (result.isHasErrors()){
throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,//
result.getErrorMsgMap().toString());
}
}
}
private ValidationResult validator(Object bean) {
final ValidationResult result = new ValidationResult();
Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(bean);
if (constraintViolationSet.size() > 0){
// 有错误
result.setHasErrors(true);
constraintViolationSet.forEach(constraintViolation -> {
String errMsg = constraintViolation.getMessage();
String propertyName = constraintViolation.getPropertyPath().toString();
result.getErrorMsgMap().put(propertyName,errMsg);
});
}
return result;
}
@Override
public void afterPropertiesSet() throws Exception {
// 将hibernate validator 通过工厂的初始化方法使其实例化
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
}
}
【5】校验测试
配置TestVo
package com.lzy.controller.viewobject;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
public class TestVo {
@NotNull
private Integer id;
@NotBlank
@Length(min = 1, max = 3, message = "名称长度在1到3个字之间")
private String name;
}
TestController-validatortest
@Resource
private ValidatorImpl validator;
@GetMapping("/validatetest")
public CommonReturnType testException(TestVo testVo) {
validator.check(testVo);
return CommonReturnType.create("success");
}
7.访问web前端页面
【1】在父级pom中配置jsp的依赖
<!--添加jstl依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--添加jsp依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
【2】在application.properties中配置jsp的访问路径
#配置jsp的访问路径
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
【3】index.jsp
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
【4】contronller测试
// 测试页面
@RequestMapping("/index.page")
public String indexPage(){
return "index";
}
测试结果: