当前位置: 首页 > news >正文

springboot 基础

巩固基础,砥砺前行 。
只有不断重复,才能做到超越自己。
能坚持把简单的事情做到极致,也是不容易的。

SpringBoot JavaEE 简介

JavaEE的局限性:
1、过于复杂,JavaEE正对的是复杂的分布式企业应用,然而现实情况是大部分应用都是比较简单,复杂的架构带来了复杂的开发方式和部署方式。

2、最求分布式,大部分引用并非都是JavaEE 嘉定的分布式系统,Spring曾经反对过这种分布式架构,并只提供了容器管理,名词获得了成功,大型应用采用分布式架构不可避免,Spring提供了其他的技术支持,eg:RestFul架构

3、不能及时和流行开源技术整合,比如消息处理,除了有了标准的JMS支持,现在还有新能更好的RabbitMQ和kalfa。JavaEE 并没有与之相对应的标准,方二十Spring,具有统一的实现消息处理模式

4、JavaEE 应用服务器都有商业公司提供价格不菲,少有公司采用管理引用服务器和部署应用对初学者和自学者有一定门槛

Spring
Spring通过ioc管理bean,通过Aop方式增强bean功能,它没有像JavaEE那样纤细规定容器提供的是何种服务和容器运行的具体组件类型。

Spring的缺点
尽管Spring很强大,但是他也有JavaEE的缺点:

1、使用门槛升高,要入门spring需要较长时间

2、对过时技术支持,导致使用复杂度升高

3、xml配置已经不再是流行的系统配置方式

4、集成第三方工具的时候,程序员还要考虑工具之间的兼容性

5、系统启动慢,不具备热部署功能,完全依赖虚拟机或者web服务器的热部署

SpringBoot
springboot简化了spring应用配置,不需要配置就能就能运行spring应用,springboot管理spring容器、第三方插件,并提供了许多默认系统级的服务。大部分的spring应用,无论是简单还是复杂,都只需要少量的配置和代码就能完成。springboot通过starter来提供系统级别的服务。在使用的时候,在pom.xml中引入对应的starter即可使用。

相比于spring,springboot优点:

1、实现约定大于配置,是一个低配置的应用系统架构,不像spring那样需要大量的配置。仅仅需要少量的配置就能完成大量的功能

2、提供了内置的tomcat或者jetty功能

3、通过加载jar包管理、自动装配技术,容易支持与其他技术体系、工具集成

4、支持热加载,开发体检好,也支持springboot监控,方便了解系统运行情况。

springboot 配置、加载

加载外部类的几种方式

  1. 使用@Configuration + @Bean 的方式引入
  2. 使用@Configuration + @ImportResource 方式引入
  3. 使用@Configuration + @Import 方式引入

加载配置文件中的属性的方式

  1. @Value(“${}”) 加载单一的配置文件
person.last-name=张三3333333333${random.uuid}
application.properties 文件中
@Value("${person.last-name}")
private String lastName;
  1. 使用@Component、@ConfigurationProperties(prefix = “person”) 从全局的默认配置文件中加载属性
@Component
@ConfigurationProperties(prefix = "person")
public class Person {}application.properties文件中
person.last-name=张三3333333333${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
  1. 使用 @Component、@ConfigurationProperties 、@PropertySource 三个注解 从指定位置加载属性
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {private String lastName;private Integer age;private Boolean boss;private Date birth;private Map<String,Object> maps;private List<Object> lists;private Dog dog;
}
classPath 路径下 person.properties 文件中
person.last-name=李四
person.age=12
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=15

profiles

application.yml 中的文档块模式


server:port: 8081
spring:profiles:active: prod  # 激活指定配置文件---
server:port: 8083
spring:profiles: dev---server:port: 8084
spring:profiles: prod  # 该文件被激活

在启动jar包的时候 动态指定jar的端口号

java -jar demo.jar --spring.profiles.active=dev

配置虚拟机参数

-Dspring.profiles.active=dev

在启动jar的时候指定外部的配置文件

 java -jar demo.jar --spring.config.location=G:/application.properties

配置文件的加载顺序

  1. 在相同位置的application.properties 和application.yml 配置文件的加载顺序:从上到下加载,谁在上就加载谁
application.propertiesserver.port=8082application.ymlserver:port: 8081

application.properties 在 application.yml 之上,所以启动的端口号 是8082

在这里插入图片描述

maven简介

maven实现的目标

  1. 是构建项目变得同意,maven屏蔽了构建的复杂过程
  2. 统一了构建下项目的方式,不同人、不同公司的羡慕都有同样的描述和构建项目的方式。maven通过pom.xml来描述项目,并提供了一系列插件来构建项目。
  3. 提出了一套开发项目的最佳实践。而不用每个项目都有不同机构和构建方式。比如源代码出现在scr/main/java中,测试代码出现在scr/main/test中,项目需要的配置文件放在scr/main/resources中
  4. 包含不同环境项目的构建方式
  5. 解决了依赖的问题,只要申明使用的类库,maven会自动冲仓库下载依赖的jar包,并能协助你管理jar之间的冲突

pom中元素介绍

groupId

表示项目所属的组,通常是一个公司或者组织的名称。如。org.springframework

artifactId

项目的唯一标识,如。spring-boot-start-web。groupId 和 artifactId 能唯一标识一个项目或者一个库,通常称之为项目坐标。

packaging

项目类型,常用的有jar和war两种

version

项目的版本号。通常来说,项目版本号分为三段,主版本、此版本、修订版本

主版本:代表脚骨变动或者不见同实现

次版本:是兼容性修改,功能增强

修订版:bug修复

modelVersion

代表pom文件的maven版本。

scope

scope 代表次类库和项目的关系,默认是compile,也就是编译和打包都需要此类库。

test:仅仅在单元测试的时候需要

provided:标识在编译阶段需要词此类库,但是打包不需要,因为项目的目标环境已经提供了

runtime:标识在编译和打包的时候都不需要,但是在运行的时候需要

build

此项目在pom中可选,build包含多个插件plugin,用来辅助构建项目


面试的时候,问过scope

spring boot 发送邮件

1.引入jar

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.application.yml配置

spring: mail: #发送消息的邮箱配置username: XXX@qq.com#password是QQ邮箱的授权码 password: snnaaprastgfdebghost: smtp.qq.comproperties: mail: smtp: ssl: enable: true

3.发送简单文本信息

@Autowired
JavaMailSenderImpl mailSender;public void testContext() {SimpleMailMessage message = new SimpleMailMessage();//邮件设置message.setSubject("Topic主题");message.setText("Message……");//发送到哪里message.setTo("XXX@163.com");//从哪里发送message.setFrom("XXX@qq.com");mailSender.send(message);
}

4.发送带有附件的


public void testAA() throws  Exception{//1、创建一个复杂的消息邮件MimeMessage mimeMessage = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);//邮件设置helper.setSubject("XXXX");helper.setText("<b style='color:red'>CCCC</b>",true);helper.setTo("15513@163.com");helper.setFrom("291506@qq.com");//上传文件helper.addAttachment("1.jpg",new File("C:\\Users\\DELL\\Pictures\\1.jpg"));helper.addAttachment("2.mp4",new File("C:\\\\Users\\\\DELL\\\\Pictures\\\\2.mp4"));mailSender.send(mimeMessage);}

springboot和redis缓存

redis缓存

1)在pom中新增

	<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2)在application.yml中新增redis配置.ookk

	spring: redis: host: localhost

3)配置redis序列化

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;@Configuration
public class MyRedisConfig {@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置value的序列化规则和 key的序列化规则redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}
  1. java操作redis工具类
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public void deleteObject(final String key){redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public void deleteObject(final Collection collection){redisTemplate.delete(collection);}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}

springboot本地缓存

缓存

本地缓存
1)启动类增加注解 @EnableCaching // 开启缓存
2)在service层代码中增加注解,进行测试
本地缓存使用的是currentHashMap

	```import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.CachePut;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import com.ttzz.bean.Dog;import com.ttzz.mapper.DataDemo;@Service/*** @CacheConfig(cacheNames = {},cacheManager=AAAA,cacheResolver = {})*/public class DogService {@Autowiredprivate DataDemo dataDemo;/*** @Cacheable:先在缓存中查找,如果没有该缓存,则创建,查询数据,放入缓存,并返回数据* 			 参数:1)cacheNames/value:* 				 2)key:* 				 3)keyGenerator:* 				 4)cacheManager:* 				 5)condition:* 				 6)unless:	* 				 7)sync:*/@Cacheable(value = "dog",/*cacheNames = ,keyGenerator = ,condition = ,unless =  ,sync = true*/key = "#id")public Dog getById(String id) {return dataDemo.getById(id);}/*** @CachePut: 先调用目标方法,然后调用缓存信息*/@CachePut(value = "dog",key="#dog.id")public void save(Dog dog) {dataDemo.save(dog);}@CachePut(value = "dog",key="#dog.id")public void update(Dog dog) {dataDemo.update(dog);}/*** @CacheEvict:* allEntries:删除整个缓存中的数据* beforeInvocation:执行方法前删除还是执行方法后删除*/@CacheEvict(value = "dog" /* allEntries = true, beforeInvocation = true*/,key="#id")public void delete(String id) {dataDemo.delete(id);}/*** @Caching:复合注解* @Caching(cacheable = {@Cacheable(value = )},put = {@CachePut()})*/}```

SpringBoot以jar启动加载外部配置文件

SpringBoot以jar启动加载外部配置文件

通常需要将SpringBoot打成jar的方式来启动,有时候也需要将配置文件放到项目(jar)外。如何访问外部的配置文件呢?


使用以下命令来操作
命令1
java -jar XXX.jar -Dspring.config.location=D:\workspace-test\work02\seed-java\seed-framework\target\_config\application.yml
命令2
java -jar D:\workspace-test\work02\seed-java\seed-framework\target\XXX.jar -Dspring.config.location=D:\workspace-test\work02\seed-java\seed-framework\target\_config\application.yml -Dspring.profiles.active=test

SpringBoot 读取应用配置文件

springboot读取配置文件有三种方式
  1. 使用environment类,可以通过key-value的方式读取到application.properties中的数据
  2. 使用@value注解,使用spel表达式,注入属性值
  3. 使用@configurationProperties注解
environment

environment是一个通用的读取应用运行时的环境变量的类,可以读取application。properties,命令函输入参数、系统属性、操作系统环境变量等

@Autowired
private Environment env;

使用方法:env.getProperty(XXXX)

@value

直接通过@value注入一个配置信息到bean

@configurationProperties

该注解可以将同样类型的配置映射成为一个类,方便使用。一般和@Configuration注解配合使用。它和@value功能差不多,它不能读取yml文件中的属性信息,@value可以,@value支持spel表达式。

SpringBoot之Jackson注解

Jackson有多个注解,用来在序列化和反序列化操作

@JsonProperty("XXXX") //为key指定一个别名
private String aa;
@JsonIgnore("XXXX") //忽略此属性
private String aa;
@JsonIgnoreProperties({"XXXX","BBBB"}) //忽略多个属性,作用在类上
private class aa{}
@JsonFormat(pattern = "yyyy-mm-dd") //忽略此属性
private Date aa;

Jackson支持三种序列化和反序列化的方式

  1. 使用JsonParser来解析json,解析结果是一串tokens,采用jsonGenerator来生成json,这是最底层的方式
  2. 采用树遍历的方式 json被读入到jsonnode对象中,可以像操作xmldom那样读取json
  3. 采用dataBind方式,将实体类对象序列化成json,或者反序列化成实体对象,这是最简单的一种。对于应用程序来说最常用的是第三种。

SpringBoot Mock代码测试

增删改查代码


import java.net.URI;
import javax.annotation.Resource;import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;@RunWith(SpringRunner.class)
@SpringBootTest(classes = XXXX.class)
@WebAppConfiguration
//配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用
@Transactional(transactionManager = "transactionManager")
@Rollback(value = true)
public class BySpecimenControllerTest {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;public String token;@Resourceprivate SysLoginService loginService;@Beforepublic void setupMockMvc() {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
//        token = }@Testpublic void testDeleteBySpecimen () throws Exception{String id = "1";mockMvc.perform(MockMvcRequestBuilders.delete("/bySpecimens/delete/"+id)
//    		.header("Authorization", "Bearer "+token+"")).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void testFindBySpecimenById() throws Exception {String id = "1";mockMvc.perform(MockMvcRequestBuilders.get(new URI("/bySpecimens/info")).param("opertationId", id)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void testFindBySpecimens () throws Exception{mockMvc.perform(MockMvcRequestBuilders.get("/bySpecimens/list")
//    			 .header("Authorization", "Bearer "+token+"")).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void testSaveBySpecimen() throws Exception {mockMvc.perform(MockMvcRequestBuilders.post("/bySpecimens/save")
//    	 		.header("Authorization", "Bearer "+token+"")// 标本标识.param("specimenId", "value") .param("status", "0") ).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void testUpdateBySpecimen () throws Exception {mockMvc.perform(MockMvcRequestBuilders.put("/bySpecimens/save")
//   	 			.header("Authorization", "Bearer "+token+"")// 标本标识.param("specimenId", "1") .param("status", "1") ).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}}
使用实体作为参数,需要在Controller 的参数 使用@RequestBody 标记A domain = new A();//设置参数//domain.setString jsonStr = JSONObject.toJSONString(domain);mockMvc.perform(MockMvcRequestBuilders.put("/As/save").header("Authorization", "Bearer "+token+"").accept(MediaType.APPLICATION_JSON_UTF8).contentType(MediaType.APPLICATION_JSON_UTF8).content(jsonStr)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());

SpringBoot+Mybatis 实现多数据源配置(基于分包管理)、Swagger配置

1.本文主要是基于分包管理来实现多数据源的方式,简单易用
2.Swagger配置

pom.xml配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>XXX</groupId><artifactId>XXX</artifactId><version>0.0.1-SNAPSHOT</version><name>sXXX</name><description>XXX</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.13.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>1.8</java.version><mybatis-plus.version>3.1.2</mybatis-plus.version><pagehelper.spring.boot.starter.version>1.2.5</pagehelper.spring.boot.starter.version><druid.version>1.1.17</druid.version><jwt.version>0.9.1</jwt.version><fastjson.version>1.2.60</fastjson.version><swagger.version>2.9.2</swagger.version><commons.version>2.6</commons.version><bitwalker.version>1.19</bitwalker.version><guava.version>26.0-jre</guava.version><commons.io.version>2.5</commons.io.version><oshi.version>3.9.1</oshi.version><seed.common.version>0.0.1-SNAPSHOT</seed.common.version><oracle.version>12.1.0.2</oracle.version></properties><dependencies><!-- https://mvnrepository.com/artifact/org.apache.clerezza.ext/org.json.simple --><dependency><groupId>org.apache.clerezza.ext</groupId><artifactId>org.json.simple</artifactId><version>0.4</version></dependency><!--常用工具类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><!--io常用工具类 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId></dependency><!-- poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.15</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version></dependency><!-- 解析客户端操作系统、浏览器等 --><dependency><groupId>eu.bitwalker</groupId><artifactId>UserAgentUtils</artifactId></dependency><!-- 获取系统信息 --><dependency><groupId>com.github.oshi</groupId><artifactId>oshi-core</artifactId></dependency><dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId></dependency><dependency><groupId>net.java.dev.jna</groupId><artifactId>jna-platform</artifactId></dependency><!--Spring框架基本的核心工具--><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><!-- pagehelper 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></exclusion></exclusions></dependency><!-- oracle 驱动 --><dependency><groupId>com.oracle</groupId><artifactId>ojdbc7</artifactId><version>12.1.0.2</version></dependency><!-- mysql 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-core</artifactId><version>5.1.8.RELEASE</version><scope>compile</scope></dependency><!-- 引入freeMarker的依赖包. --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>net.hasor</groupId><artifactId>hasor-spring</artifactId><version>4.1.3</version></dependency><dependency><groupId>net.hasor</groupId><artifactId>hasor-dataway</artifactId><version>4.1.3-fix20200414</version><!-- 4.1.3 包存在UI资源缺失问题 --></dependency><!-- 集成SpringMvc框架并实现自动配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!-- json --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!-- oracle驱动 --><!--<dependency><groupId>com.oracle</groupId><artifactId>ojdbc7</artifactId><version>${oracle.version}</version></dependency>--><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- Swagger API文档 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${swagger.version}</version><exclusions><exclusion><groupId>io.swagger</groupId><artifactId>swagger-annotations</artifactId></exclusion><exclusion><groupId>io.swagger</groupId><artifactId>swagger-models</artifactId></exclusion></exclusions></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>${swagger.version}</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-bean-validators</artifactId><version>${swagger.version}</version></dependency><!-- 防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.22版本 --><dependency><groupId>io.swagger</groupId><artifactId>swagger-annotations</artifactId><version>1.5.22</version></dependency><dependency><groupId>io.swagger</groupId><artifactId>swagger-models</artifactId><version>1.5.22</version></dependency><!-- 测试单元 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><!-- pagehelper 分页插件 --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>${pagehelper.spring.boot.starter.version}</version></dependency><!--io常用工具类 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>${commons.io.version}</version></dependency><!-- 解析客户端操作系统、浏览器等 --><dependency><groupId>eu.bitwalker</groupId><artifactId>UserAgentUtils</artifactId><version>${bitwalker.version}</version></dependency><!-- 获取系统信息 --><dependency><groupId>com.github.oshi</groupId><artifactId>oshi-core</artifactId><version>${oshi.version}</version></dependency></dependencies></dependencyManagement></project>

多数据源配置代码

1.主数据源配置

@Primary 标注的是主数据源

import javax.sql.DataSource;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;@Configuration
@MapperScan(basePackages = {"包路径.mapper.数据库标识1mapper" }, annotationClass = Mapper.class, sqlSessionFactoryRef = "数据库标识1SqlSessionFactory")
public class 数据库标识1MybatisConfig {/*** @return 返回DataSource对象*/@Bean(name = "数据库标识1DataSource")@Qualifier("数据库标识1DataSource")@ConfigurationProperties(prefix = "spring.datasource.数据库标识1")@Primarypublic DataSource cmsDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "数据库标识1SqlSessionFactory")@Primarypublic SqlSessionFactory sqlSessionFactory(@Qualifier("数据库标识1DataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);sqlSessionFactoryBean.setMapperLocati数据库标识1(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/数据库标识1mapper/*.xml"));return sqlSessionFactoryBean.getObject();}@Bean(name = "数据库标识1PlatformTransactionManager")public PlatformTransactionManager transactionManager(@Qualifier("数据库标识1DataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean("数据库标识1SqlSessionTemplate")// 表示这个数据源是默认数据源@Primarypublic SqlSessionTemplate test1sqlsessiontemplate(@Qualifier("数据库标识1SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);}
}

2.第二个数据源配置

如何扩展 第三、第四数据源呢?
(1)复制第二数据源配置类,简单修改注解中的名称
(2)在resource的mapper文件夹下创建XXXmapper,用来存放XXXXMapper.xml文件
特别注意没有primary修饰了哦

import javax.sql.DataSource;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;@Configuration
@MapperScan(basePackages = {"包路径.mapper.数据库标识2mapper" }, annotationClass = Mapper.class, sqlSessionFactoryRef = "数据库标识2SqlSessionFactory")
public class 数据库标识2MybatisConfig {/*** @return 返回DataSource对象*/@Bean(name = "数据库标识2DataSource")@Qualifier("数据库标识2DataSource")@ConfigurationProperties(prefix = "spring.datasource.数据库标识2")public DataSource cmsDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "数据库标识2SqlSessionFactory")@Primarypublic SqlSessionFactory sqlSessionFactory(@Qualifier("数据库标识2DataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);sqlSessionFactoryBean.setMapperLocati数据库标识2(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/数据库标识2mapper/*.xml"));return sqlSessionFactoryBean.getObject();}@Bean(name = "数据库标识2PlatformTransactionManager")public PlatformTransactionManager transactionManager(@Qualifier("数据库标识2DataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean("数据库标识2SqlSessionTemplate")// 表示这个数据源是默认数据源@Primarypublic SqlSessionTemplate test1sqlsessiontemplate(@Qualifier("数据库标识2SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);}
}

resource下application.yml 中的数据源信息配置信息

spring:profiles: active: devmvc: static-path-pattern: /**resource: static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/datasource:
#数据库标识1数据源配置数据库标识1: jdbc-url: jdbc:mysql://ip:3306/d1?useUnicode=true&characterEncoding=utf8&useSSL=falseusername: XXXpassword: XXXmaxActive: 50initialSize: 10maxWait: 60000minIdle: 1timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000maxOpenPreparedStatements: 2type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverfilters: statvalidationQuery: select version()testWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true
#数据库标识2数据源配置数据库标识2:jdbc-url: jdbc:oracle:thin:@ip:1521:XXXusername: XXXpassword: XXXmaxActive: 50initialSize: 5maxWait: 60000minIdle: 1timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000maxOpenPreparedStatements: 2type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: oracle.jdbc.OracleDriverfilters: statvalidationQuery: select * from dualtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true

Swagger类配置 SwaggerConfig.java

import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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.ApiKey;
import springfox.documentation.service.Contact;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
public class SwaggerConfig {/*** 创建API*/@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).enable(true).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build()/* 设置安全模式,swagger可以设置访问token */.securitySchemes(securitySchemes()).securityContexts(securityContexts());}/*** 安全模式,这里指定token通过Authorization头请求头传递*/private List<ApiKey> securitySchemes() {List<ApiKey> apiKeyList = new ArrayList<ApiKey>();apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));return apiKeyList;}/*** 安全上下文*/private List<SecurityContext> securityContexts() {List<SecurityContext> securityContexts = new ArrayList<>();securityContexts.add(SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.regex("^(?!auth).*$")).build());return securityContexts;}/*** 默认的安全上引用*/private List<SecurityReference> defaultAuth() {AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];authorizationScopes[0] = authorizationScope;List<SecurityReference> securityReferences = new ArrayList<>();securityReferences.add(new SecurityReference("Authorization", authorizationScopes));return securityReferences;}/*** 添加摘要信息*/private ApiInfo apiInfo() {// 用ApiInfoBuilder进行定制return new ApiInfoBuilder()// 设置标题.title("XXXX_接口文档")// 描述.description("XXXX所有API接口")// 作者信息.contact(new Contact("XXXX", null, null))// 版本.version("版本号:1.0" ).build();}
}

SpringBoot引入外部jar,并将项目打包成jar包,引发项目运行失败的问题

SpringBoot引入外部jar,并将项目打包成jar包

正常打包操作
  • 在src/main/resource 目录下创建一个lib文件夹,将需要打如到项目中的jar放在这里
  • 通过build path 将这些jar加入到工程中,以方便调用
  • 在pom.xml中增加,其中xxx看实际情况而定
	<dependencies><dependency><groupId>XXX</groupId><artifactId>XXX</artifactId><version>XXX</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/XXX.jar</systemPath></dependency></dependencies>
  • 在pom.xml中增加build 逻辑
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins><resources><resource><directory>lib</directory><targetPath>BOOT-INF/lib/</targetPath><includes><include>**/*.jar</include></includes></resource><resource><directory>src/main/resources</directory><targetPath>BOOT-INF/classes/</targetPath></resource></resources></build>
特别注意: 上面的build中的代码仅仅是在打包的时候打开,在运行项目的时候,需要将上面的代码注释掉。不然会报错:找不到XXXMapper.xml mybatis对应的xml文件。

【转载】springboot引入外部依赖jar包


今天项目(springboot项目)中需要导入外部的jar包,在打包的时候需要将外部jar打到项目中。就这一个问题,CSDN中有好多的提示的文章。真TM傻逼啊,发文章之前,自己就不测试一下吗?自己在网上随便找一个案例,正好满足自己的要求,就直接用了,标题都TM不调整一下,也不看看人家的标题和你自己写的是不是一个意思。误人子弟。

正解文件连接:

springboot引入外部依赖jar包_springboot引入外部jar包_半山惊竹的博客-CSDN博客

RestTemplateUtil 工具类

两个系统之间做数据交互,一般都是使用接口的方式,在SpringBoot中提供了一个RestTemplate类,方便调用。

以下是一个简单封装,方便使用
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;import com.alibaba.fastjson.JSONObject;import lombok.extern.slf4j.Slf4j;@Slf4j
public class RestTemplateUtil {/*** restTemplate 发送post请求* @param restTemplate* @param url* @param json* @return*/public static ResponseEntity<String> getRestTemplatePost(RestTemplate restTemplate,String url,String json){HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));headers.setContentType(MediaType.APPLICATION_JSON_UTF8);HttpEntity<String> requestEntity = new HttpEntity<String>(json,headers);ResponseEntity<String> entity = restTemplate.postForEntity(url, requestEntity, String.class);return entity;}/*** restTemplate 发送get请求* @param restTemplate* @param url* @param json* @return*/public static ResponseEntity<String> getRestTemplateGet(RestTemplate restTemplate,String url,String json){HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));headers.setContentType(MediaType.APPLICATION_JSON_UTF8);HttpEntity<String> requestEntity = new HttpEntity<String>(json,headers);ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class,json);return entity;}public static Map<String, String> parseResponseEntity(ResponseEntity<String> entity) {Map<String,String> map = new HashMap<String,String>();log.info("ResponseEntity="+JSONObject.toJSONString(entity));Integer code = entity.getStatusCodeValue();if(entity.getStatusCodeValue()==200) {JSONObject obj = JSONObject.parseObject(entity.getBody());map.put("code", code+"");map.put("data", obj.getString("data").toString());}log.info(JSONObject.toJSONString(map));return map;}}

关于@Transactional 的sao操作

关于@Transactional 作用的一些测试

    • SpringBoot JavaEE 简介
    • springboot 配置、加载
      • 加载外部类的几种方式
      • 加载配置文件中的属性的方式
      • profiles
        • 在启动jar包的时候 动态指定jar的端口号
        • 配置虚拟机参数
        • 在启动jar的时候指定外部的配置文件
      • 配置文件的加载顺序
    • maven简介
        • maven实现的目标
        • pom中元素介绍
          • groupId
          • artifactId
          • packaging
          • version
        • modelVersion
        • scope
        • build
    • spring boot 发送邮件
      • 1.引入jar
      • 2.application.yml配置
      • 3.发送简单文本信息
      • 4.发送带有附件的
    • springboot和redis缓存
      • redis缓存
    • springboot本地缓存
      • 缓存
    • SpringBoot以jar启动加载外部配置文件
  • SpringBoot以jar启动加载外部配置文件
          • 使用以下命令来操作
            • 命令1
            • 命令2
    • SpringBoot 读取应用配置文件
          • springboot读取配置文件有三种方式
            • environment
            • @value
            • @configurationProperties
    • SpringBoot之Jackson注解
        • Jackson支持三种序列化和反序列化的方式
    • SpringBoot Mock代码测试
    • SpringBoot+Mybatis 实现多数据源配置(基于分包管理)、Swagger配置
      • pom.xml配置
      • 多数据源配置代码
        • 1.主数据源配置
        • 2.第二个数据源配置
        • resource下application.yml 中的数据源信息配置信息
      • Swagger类配置 SwaggerConfig.java
    • SpringBoot引入外部jar,并将项目打包成jar包,引发项目运行失败的问题
            • 正常打包操作
            • **特别注意:** 上面的build中的代码仅仅是在打包的时候打开,在运行项目的时候,需要将上面的代码注释掉。不然会报错:找不到XXXMapper.xml mybatis对应的xml文件。
    • 【转载】springboot引入外部依赖jar包
    • RestTemplateUtil 工具类
            • 以下是一个简单封装,方便使用
    • 关于@Transactional 的sao操作
      • case1 无try catch、无嵌套,没有加 rollbackFor = Exception.class 事务正常回滚
      • case2 无try catch、无嵌套,加 rollbackFor = Exception.class 事务正常回滚
      • case3 没有加 rollbackFor = Exception.class 事务没有回滚
      • case4 有try catch、无嵌套,加 rollbackFor = Exception.class 事务没有回滚
      • case5 有try catch、无嵌套,加 rollbackFor = Exception.class ,抛出异常 。 事务正常回滚
      • case6 有try catch、无嵌套,加 rollbackFor = Exception.class ,抛出异常。方法调用,事务没有回滚
      • case7 事务没有回滚
      • case8 事务回滚
      • case9 事务回滚
      • case10 事务未回滚
      • case11 事务回滚
      • case12 事务未回滚
      • case13 事务回滚
      • case14 事务回滚
      • case15 事务回滚
    • dynamic-datasource 使用

在使用@Transactional  关键字的时候,总会有这样 或者 那有的问题。一下做一些测试来验证问题

case1 无try catch、无嵌套,没有加 rollbackFor = Exception.class 事务正常回滚

@Transactionalpublic int testSave()  {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;}

case2 无try catch、无嵌套,加 rollbackFor = Exception.class 事务正常回滚

@Transactional(rollbackFor = Exception.class)public int testSave()  {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;}

case3 没有加 rollbackFor = Exception.class 事务没有回滚

@Transactionalpublic int testSave()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {// TODO: handle exception}return 0;}

case4 有try catch、无嵌套,加 rollbackFor = Exception.class 事务没有回滚

@Transactional(rollbackFor = Exception.class)public int testSave()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {// TODO: handle exception}return 0;}

case5 有try catch、无嵌套,加 rollbackFor = Exception.class ,抛出异常 。 事务正常回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {throw new Exception(e.getMessage());}}

case6 有try catch、无嵌套,加 rollbackFor = Exception.class ,抛出异常。方法调用,事务没有回滚

public int testSave() throws Exception {return testSave2();}@Transactional(rollbackFor = Exception.class)public int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case7 事务没有回滚

@Transactionalpublic int testSave() throws Exception {return testSave2();}@Transactional(rollbackFor = Exception.class)public int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case8 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {return testSave2();}public int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case9 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {return testSave2();}@Transactional(rollbackFor = Exception.class)public int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case10 事务未回滚

@Transactionalpublic int testSave() throws Exception {return testSave2();}@Transactional(rollbackFor = Exception.class)public int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case11 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {return testSave2();}@Transactionalpublic int testSave2() throws Exception  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());throw new Exception(e.getMessage());}}

case12 事务未回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {return testSave2();}@Transactionalpublic int testSave2()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);int m = 1/0;return 1;} catch (Exception e) {System.out.println(e.getMessage());}return 0;}

case13 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {int m =  testSave2();int n = 1/0;return m;}@Transactionalpublic int testSave2()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);return 1;} catch (Exception e) {System.out.println(e.getMessage());}return 0;}

case14 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {int m =  testSave2();int n = 1/0;return m;}public int testSave2()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);return 1;} catch (Exception e) {System.out.println(e.getMessage());}return 0;}

case15 事务回滚

@Transactional(rollbackFor = Exception.class)public int testSave() throws Exception {int m =  testSave2();int n = 1/0;return m;}@Transactional(rollbackFor = Exception.class)public int testSave2()  {try {User user = new User();user.setName("岳不群2");user.setAge(70);user.setEmail("lucy@qq.com");userMapper.insert(user);return 1;} catch (Exception e) {System.out.println(e.getMessage());}return 0;}

dynamic-datasource 使用

1)在项目中引入dynamic-datasource该modul
2)在application.yml中添加

dynamic:datasource:slave1: driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:XXX:orcl_tjhusername: XXpassword: XXvalidation-query: SELECT 1 FROM DUALslave2: driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/XXX?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: XXXXpassword: XXXX
  1. 在项目中使用,dynamic 配置的都是子数据源。
    在访问的service 方法上 使用@DataSource(数据源表示);如上的slave1

【临渊羡鱼不如退而结网】

相关文章:

springboot 基础

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 SpringBoot JavaEE 简介 JavaEE的局限性&#xff1a; 1、过于复杂&#xff0c;JavaEE正对的是复杂的分布式企业应用&#xff0c;然而现实…...

web集群学习:基于nginx的反向代理和负载均衡

目录 一&#xff0c;反向代理 1&#xff0c;环境准备 2&#xff0c;配置代理服务器 3&#xff0c;在物理机上一管理员身份打开文本编辑器&#xff0c;编辑C:\Windows\System32\drivers\etc目录下的hosts文件 4&#xff0c;访问测试 5&#xff0c;查看日志&#xff0c;并记…...

编程小窍门: 一个简单的go mutex的小例子

本期小窍门用到了两个组件 mutex 这个类似其他语言的互斥锁waitGroup 这个类似其他语言的信号量或者java的栅栏锁 示例如下 func TestDoSomething04(t *testing.T) {total : 0var wg sync.WaitGroup{}var mut sync.Mutex{} for i : 0; i < 5000; i {go func() {wg.Ad…...

【工作记录】mysql中实现分组统计的三种方式

前言 实际工作中对范围分组统计的需求还是相对普遍的&#xff0c;本文记录下在mysql中通过函数和sql完成分组统计的实现过程。 数据及期望 比如我们获取到了豆瓣电影top250&#xff0c;现在想知道各个分数段的电影总数. 表数据如下: 期望结果: 实现方案 主要思路是根据s…...

马来西亚的区块链和NFT市场调研

马来西亚的区块链和NFT市场调研 基本介绍 参考&#xff1a; https://zh.wikipedia.org/wiki/%E9%A9%AC%E6%9D%A5%E8%A5%BF%E4%BA%9A zz制度&#xff1a;联邦议会制 语言文字&#xff1a; 马来语 民族&#xff1a; 69.4%原住民&#xff08;土著&#xff09;&#xff0c;23.2%…...

[保研/考研机试] KY109 Zero-complexity Transposition 上海交通大学复试上机题 C++实现

描述&#xff1a; You are given a sequence of integer numbers. Zero-complexity transposition of the sequence is the reverse of this sequence. Your task is to write a program that prints zero-complexity transposition of the given sequence. 输入描述&#xf…...

Linux零基础快速入门到精通

一、操作系统概述 二、初始Linux Linux的诞生 Linux内核 Linux发行版 小结 三、虚拟机 认识虚拟机 虚拟化软件及安装 VMware Workstation 17 Pro安装教程https://blog.csdn.net/weixin_62332711/article/details/128695978 远程连接Linux系统 小结 扩展-虚拟机快照 …...

ARM02汇编指令

文章目录 一、keil软件介绍1.1 创建工程1.2 解析start.s文件(重点)1.3 乱码解决1.4 更换背景颜色1.5 C语言内存分布1.6 解析map.lds文件(重点)1.7 常见错误信息1.8 仿真 二、汇编三种符号2.1 汇编指令2.2 伪指令2.3 伪操作 三、汇编指令格式3.1 格式3.2 注意事项 四、数据操作指…...

从初学者到专家:Java方法的完整指南

目录 一.方法的概念及使用 1.1什么是方法 1.2方法的定义 1.3方法的调用 1.4实参和形参的关系 1.5没有返回值的方法 1.6方法的意义 二.方法重载 2.1方法重载的实现 2.2方法重载的意义 2.3方法签名 一.方法的概念及使用 1.1什么是方法 方法就是一个代码片段. 类似于 …...

【生成式AI】ProlificDreamer论文阅读

ProlificDreamer 论文阅读 Project指路&#xff1a;https://ml.cs.tsinghua.edu.cn/prolificdreamer/ 论文简介&#xff1a;截止2023/8/10&#xff0c;text-to-3D的baseline SOTA&#xff0c;提出了VSD优化方法 前置芝士:text-to-3D任务简介 text-to-3D Problem text-to-3D…...

C++元编程——模拟javascript异步执行

javascript有一个期约调用&#xff0c;就是利用内部的一种协程机制实现的类似并行的操作。以下是用ChatGPT搞出来的一块演示代码&#xff1a; // 异步任务 function asyncTask() {return new Promise((resolve, reject) > {setTimeout(() > {const randomNumber Math.f…...

【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态SQL

【JavaEE】MyBatis框架要点总结&#xff08;3&#xff09; 文章目录 【JavaEE】MyBatis框架要点总结&#xff08;3&#xff09;1. 多表查询1.1 映射表resultMap1.2 只有部分属性跨表查询1.2.1 依照常规去写代码1.2.2 用标签去实现接口 1.3 分多步的解决方案1.4 与多线程的结合 …...

Springboot 默认路径说明

Spring Boot基本上是Spring框架的扩展&#xff0c;它消除了设置Spring应用程序所需的样板配置&#xff0c;极大的方便了开发者&#xff0c;其默认识别路径如下&#xff1a; Spring Boot 作为Spring默认将 /** 所有访问映射到以下目录&#xff1a; 1、classpath:/static 用于加…...

springboot注册拦截器与返回统一标准响应格式

响应对象ResultVO package com.example.poi.utils;import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.io.Serializable;/*** A…...

卷王特斯拉又全网降价了,卷死车企们

哈喽,大家好,今天媒介盒子小编又来跟大家分享软文推广的干货知识了,本篇分享的主要内容是&#xff1a;特斯无孔不入的营销手段。 1、特斯拉Model Y降价 车企要打架 自2023 年 8 月 14 日起&#xff0c;Model Y 长续航版起售价从 31.39 万元调整为 29.99 万元&#xff0c;Mode…...

wiley:revision 流程

1 上传修改后的word文件 注意&#xff1a;包括没标注修改位置的word文件和标注了修改位置的word文件 2 上传response回复文件 Your Author Response should include relevant comments that you have copied from the decision letter, along with your comments detailing …...

【论文阅读】基于深度学习的时序预测——Pyraformer

系列文章链接 论文一&#xff1a;2020 Informer&#xff1a;长时序数据预测 论文二&#xff1a;2021 Autoformer&#xff1a;长序列数据预测 论文三&#xff1a;2022 FEDformer&#xff1a;长序列数据预测 论文四&#xff1a;2022 Non-Stationary Transformers&#xff1a;非平…...

玩转IndexedDB,比localStorage、cookie还要强大的网页端本地缓存

随着浏览器的功能不断增强&#xff0c;越来越多的网站开始考虑&#xff0c;将大量数据储存在客户端&#xff0c;这样可以减少从服务器获取数据&#xff0c;直接从本地获取数据。 现有的浏览器数据储存方案&#xff0c;都不适合储存大量数据&#xff1a;Cookie 的大小不超过 4K…...

RedisDesktopManager连不上redis问题解决(小白版)

常见问题就是 redis.conf配置文件 a.将port 127.0.0.1这一行注释掉 b.protected-mode保护模式改为no 这个可以看到很多博主都说了&#xff0c;相信都搜到这里来了你们都弄了&#xff0c;我就不详细说了 防火墙开放端口 我说明我自己的问题以及解决方法 1、执行telnet 虚拟…...

蓝帽杯 取证2022

网站取证 网站取证_1 下载附件 并解压 得到了一个文件以及一个压缩包 解压压缩包 用火绒查病毒 发现后门 打开文件路径之后 发现了一句话木马 解出flag 网站取证_2 让找数据库链接的明文密码 打开www文件找找 查看数据库配置文件/application/database.php&#xff08;CodeI…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...