@[TOC]
SpringBoot integration Druid+ Global transaction management +Mybatis-Plus+ code generator
Druid, global transaction management, and code generators are all very useful in SpringBoot development
Integrate Druid connection pool
Springboot’s default connection pool is HikariCP, but Druid’s capabilities are relatively comprehensive. Druid connection pooling
Step 1: Introduce the relevant JARS
< the dependency > < groupId > com. Alibaba < / groupId > < artifactId > druid - spring - the boot - starter < / artifactId > < version > 1.1.22 < / version > </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>Copy the code
Step 2: Configure related parameters
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
name: Data source name
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: JDBC: mysql: / / 127.0.0.1:3306 / springboot? characterEncoding=utf8&useSSL=false
Connection pool configuration information
# initialize size, min, Max
initial-size: 5
min-idle: 5
maxActive: 20
Set the connection wait timeout
maxWait: 60000
Configure how often to detect idle connections that need to be closed, in milliseconds
timeBetweenEvictionRunsMillis: 60000
Set the minimum time for a connection to live in the pool in milliseconds
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
Turn on PSCache and specify the size of PSCache on each connection
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# Configure the filters for monitoring statistics interception. After removing the filters, the MONITORING interface SQL cannot be counted. 'wall' is used for the firewall
filters: stat,wall,slf4j,config
Enable mergeSql via connectProperties; Slow SQL record
connectionProperties: druid.stat.mergeSql\=true; druid.stat.slowSqlMillis\=5000
web-stat-filter:
enabled: true
url-pattern: "/"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
stat-view-servlet:
enabled: true
url-pattern: "/druid/*"
login-username: admin Druid allows users to access the Druid visual interface without having to log in
login-password: 123456 # login password
reset-enable: false
allow: "" # whitelist indicates all
deny: 192.1681.12. # blacklist
Copy the code
Step 3: in the middle of the browser input: http://127.0.0.1:8080/druid/index.html can enter the visual interface
Global transaction manager
Adding transactions to SpringBoot can be done directly using the @Transactional annotation, but it is more difficult to add transactions to each method. You can add a global transaction manager directly by cutting the Transactional annotation. The caveat is to pay attention to the problem at the beginning of the method name
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
/ * * * configuration of global transaction point of contact for all methods of the service layer AOP aspects expression (https://blog.csdn.net/ycf921244819/article/details/106599489) * TODO for reference Set the location of the service layer */
private static final String AOP_POINTCUT_EXPRESSION = "execution (* cn.hjljy.fastboot.. *.service.. *. * (..) )";
/** * inject transaction manager */
@Autowired
private TransactionManager transactionManager;
/** * Configure transaction interceptor */
@Bean
public TransactionInterceptor txAdvice(a) {
RuleBasedTransactionAttribute txAttrRequired = new RuleBasedTransactionAttribute();
txAttrRequired.setName("The REQUIRED transaction");
// Set the transaction propagation mechanism, PROPAGATION_REQUIRED: If a transaction currently exists, join it; If there is no transaction currently, a new transaction is created
txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// Set the Exception rollback to Exception the default is RuntimeException
List<RollbackRuleAttribute> rollbackRuleAttributes = new ArrayList<>();
rollbackRuleAttributes.add(new RollbackRuleAttribute(Exception.class));
txAttrRequired.setRollbackRules(rollbackRuleAttributes);
RuleBasedTransactionAttribute txAttrRequiredReadOnly = new RuleBasedTransactionAttribute();
txAttrRequiredReadOnly.setName("The SUPPORTS transaction");
// Set the transaction propagation mechanism, PROPAGATION_SUPPORTS: If a transaction currently exists, join it; If there is no transaction currently, it continues in a non-transactional manner
txAttrRequiredReadOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
// Set the Exception rollback to Exception the default is RuntimeException
txAttrRequiredReadOnly.setRollbackRules(rollbackRuleAttributes);
txAttrRequiredReadOnly.setReadOnly(true);
/* Transaction management rule, which declares the name of the method with transaction management */
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
// The method name must start with the following before it is added to transaction management
source.addTransactionalMethod("add*", txAttrRequired);
source.addTransactionalMethod("save*", txAttrRequired);
source.addTransactionalMethod("create*", txAttrRequired);
source.addTransactionalMethod("insert*", txAttrRequired);
source.addTransactionalMethod("submit*", txAttrRequired);
source.addTransactionalMethod("del*", txAttrRequired);
source.addTransactionalMethod("remove*", txAttrRequired);
source.addTransactionalMethod("update*", txAttrRequired);
source.addTransactionalMethod("exec*", txAttrRequired);
source.addTransactionalMethod("set*", txAttrRequired);
// For the query method, add transaction management according to the actual situation
source.addTransactionalMethod("get*", txAttrRequiredReadOnly);
source.addTransactionalMethod("select*", txAttrRequiredReadOnly);
source.addTransactionalMethod("query*", txAttrRequiredReadOnly);
source.addTransactionalMethod("find*", txAttrRequiredReadOnly);
source.addTransactionalMethod("list*", txAttrRequiredReadOnly);
source.addTransactionalMethod("count*", txAttrRequiredReadOnly);
source.addTransactionalMethod("is*", txAttrRequiredReadOnly);
return new TransactionInterceptor(transactionManager, source);
}
/** * sets the section */
@Bean
public Advisor txAdviceAdvisor(a) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return newDefaultPointcutAdvisor(pointcut, txAdvice()); }}Copy the code
Integration of Mybatis – Plus
Step 1: Introduce the JAR package
< the dependency > < groupId > com. Baomidou < / groupId > < artifactId > mybatis - plus - the boot - starter < / artifactId > < version > 3.3.2 rainfall distribution on 10-12 < / version > </dependency>Copy the code
Step 2: Add configuration information
mybatis-plus:
mapper-locations: classpath:mapper/*.xml The default location of XML is the mapper class sibling
configuration:
mapUnderscoreToCamelCase: true # Enable Hump matching Default is true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl Print the SQL statement and input parameter data
global-config:
db-config:
logic-delete-value: 1 # Logical delete with @tablelogic annotation
logic-not-delete-value: 0 # Logic does not delete
update-strategy: not_null If a field is null, the field will not be updated.
insert-strategy: not_null Mysql > insert table (s) into table (s)
Copy the code
Step 3: Add paging and Mapper scanning
@Configuration
@MapperScan("cn.hjljy.fastboot.mapper")
public class MybatisPlusConfiguration {
/** * Mybatis -plus paging plugin */
@Bean
public PaginationInterceptor paginationInterceptor(a) {
PaginationInterceptor page = new PaginationInterceptor();
// Set the paging database type
page.setDbType(DbType.MYSQL);
page.setDialect(new MySqlDialect());
// Optimize count SQL
page.setCountSqlParser(new JsqlParserCountOptimize(true));
// Set the maximum value per page
page.setLimit(999L);
returnpage; }}Copy the code
Step 4: Create a Mapper class derived from BaseMapper, which is easy to use. Can refer to the official documentation introduction: mp.baomidou.com/guide/quick…
Integrated code generator
AutoGenerator is the code generator of MyBatis-Plus, through which the code of Entity, Mapper, Mapper XML, Service, Controller and other modules can be generated quickly. Greatly improved the development efficiency
Since the dTO and Po fields are the same in most cases, the DTO is not officially provided, so you can make a copy of entity.java.vm and change it to to.java.vm under the Resources directory. Then follow the custom prompts to modify. The specific results are as follows:
package$! {cfg.dtoPackage}; #foreach($pkg in ${table.importPackages})import ${pkg};
#end
#if(${swagger2})
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#end
#if(${entityLombokModel})
import lombok.Data;
import lombok.EqualsAndHashCode;
#if(${chainModel})
import lombok.experimental.Accessors;
#end
#end
/** * <p> * $! {table.comment} * </p> * *@author ${author}
* @since ${date}
*/
#if(${entityLombokModel})
@Data
#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)
#else
@EqualsAndHashCode(callSuper = false)
#end
#if(${chainModel})
@Accessors(chain = true)
#end
#end
#if(${table.convert})
@TableName("${table.name}")
#end
#if(${swagger2})
@apiModel (value="${entity}Dto object ", description="$! {table.comment}")
#end
#if(${superEntityClass})
public class ${entity}Dto extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity}Dto extends Model<${entity}> {
#else
public class ${entity}Dto implements Serializable {
#end
#if(${entitySerialVersionUID})
private static final long serialVersionUID=1L; # end # # -- -- -- -- -- -- -- -- -- -- BEGIN field to iterate over -- -- -- -- -- -- -- -- -- -- # foreach ($field in ${table. The fields}) #if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!!! field.comment"! ="")
#if(${swagger2})
@ApiModelProperty(value = "${field.comment}")
#else
/** * ${field.comment} */
#end
#end
#if(${field.keyflag}) ## primary key #if(${field.keyIdentityFlag})
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)#elseif(! $null.isNull(${idType}) && "$!!! idType"! ="")
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
#elseif(${field.convert})
@TableId("${field.annotationColumnName}")# end # # # ordinary field elseif (${field. The fill}) # # -- -- -- -- -- is the fields Settings -- -- -- -- - #if(${field.convert})
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
#else
@TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
@TableField("${field.annotationColumnName}")#end ## Optimistic lock annotation #if(${versionFieldName}==${field.name})
@Version#end ## Remove comment # logicallyif(${logicDeleteFieldName}==${field.name})
@TableLogic
#end
private${field.propertyType} ${field.propertyName}; The #end ## ---------- end field loops over ---------- #if(! ${entityLombokModel}) #foreach($field in ${table.fields}) #if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
#if(${chainModel})
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#else
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#end
this.${field.propertyName} = ${field.propertyName};
#if(${chainModel})
return this;
#end
}
#end
## --foreach end---
#end
## --end of #if(! ${entityLombokModel})-- #if(${entityColumnConstant})
#foreach($field in ${table.fields})
public static final String ${field.name.toUpperCase()} = "${field.name}";
#end
#end
#if(${activeRecord})
@Override
protected Serializable pkVal(a) {#if(${keyPropertyName})
return this.${keyPropertyName};
#else
return null;
#end
}
#end
#if(! ${entityLombokModel})@Override
public String toString(a) {
return "${entity}{" +
#foreach($field in ${table.fields})
#if($! {foreach.index}==0)
"${field.propertyName}=" + ${field.propertyName} +
#else
", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
"}";
}
#end
}
Copy the code
The execution code of the specific code generator is as follows:
public class CodeGenerator {
public static void main(String[] args) {
// Code generator
AutoGenerator mpg = new AutoGenerator();
// Global configuration
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("Haijal Golden Eagle (www.hjljy.cn)");
gc.setOpen(false);
// Set the entity class suffix
gc.setEntityName("%sPo");
// Entity attribute Swagger2 annotation
gc.setSwagger2(true);
gc.setBaseColumnList(true);
gc.setBaseResultMap(true);
mpg.setGlobalConfig(gc);
// Data source configuration
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/springboot? serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
/ / package configuration
PackageConfig pc = new PackageConfig();
pc.setModuleName(null);
String scanner = scanner("Please enter the overall business package name");
String modelName = StringUtils.isBlank(scanner) ? "" : "."+scanner;
//moduleName is an integral module
pc.setParent("cn.hjljy.fastboot");
pc.setMapper("mapper"+modelName);
pc.setService("service"+modelName);
pc.setServiceImpl("service"+modelName+".impl");
pc.setEntity("pojo"+modelName+".po");
pc.setController("controller"+modelName);
mpg.setPackageInfo(pc);
String dtoPath = pc.getParent() + ".pojo.dto";
// Configure the template
TemplateConfig templateConfig = new TemplateConfig();
The default generated XML is in the mapper layer
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// Configure the custom output file XML and DTO
// The template engine is Velocity
String xmlTemplatePath = "/templates/mapper.xml.vm";
// Customize the output configuration
List<FileOutConfig> focList = new ArrayList<>();
// Custom configurations are printed first
focList.add(new FileOutConfig(xmlTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// Customize the output file name. If your Entity has a prefix or suffix, note that the XML name will change accordingly!!
return projectPath + "/src/main/resources/mapper/" + scanner
+ "/" + tableInfo.getEntityName() + "Mapper"+ StringPool.DOT_XML; }}); String dtoTemplatePath ="/dto.java.vm";
// Custom configurations are printed first
focList.add(new FileOutConfig(dtoTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// Customize the output file name. If your Entity has a prefix or suffix, note that the XML name will change accordingly!!
return projectPath + "/src/main/java/cn/hjljy/fastboot/pojo/"+scanner+"/dto/" +
tableInfo.getEntityName() + "Dto"+ StringPool.DOT_JAVA; }});// Custom configuration
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap(a) {
Map<String, Object> map = new HashMap<>();
map.put("dtoPackage", dtoPath);
this.setMap(map); }}; cfg.setFileOutConfigList(focList); mpg.setCfg(cfg);// Policy configuration
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude(scanner("Table name, separated by multiple Commas").split(","));
strategy.setControllerMappingHyphenStyle(true);
// Set the logical delete field
strategy.setLogicDeleteFieldName("status");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new VelocityTemplateEngine());
mpg.execute();
}
/** * * read the console contents *
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("Please enter" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
returnipt; }}throw new MybatisPlusException("Please enter the correct one" + tip + "!"); }}Copy the code
conclusion
It’s a very basic thing in the framework. But can improve a lot of development efficiency!!