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.properties

server.port=8082

application.yml

server:
  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: snnaaprastgfdebg
    host: smtp.qq.com
    properties: 
      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 {
	@Bean
	public 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
{
    @Autowired
    public 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 {
		@Autowired
		private 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 {

	@Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;
    
    public String token;
    @Resource
    private SysLoginService loginService;
    
    @Before
    public void setupMockMvc() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
//        token = 
    }
    

     @Test
     public 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());
     }


    @Test
    public 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());
    }

    @Test
    public void testFindBySpecimens () throws Exception{
        
        mockMvc.perform(MockMvcRequestBuilders.get("/bySpecimens/list")
//    			 .header("Authorization", "Bearer "+token+"")
    		 )
    	 		 
         .andExpect(MockMvcResultMatchers.status().isOk())
         .andDo(MockMvcResultHandlers.print());
        
    }

    @Test
    public 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());
         
    }


    @Test
    public 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.set
	 String 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")
    @Primary
    public DataSource cmsDataSource() {
    	return DataSourceBuilder.create().build();
    }
	
	@Bean(name = "数据库标识1SqlSessionFactory")
	@Primary
	public 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")
	// 表示这个数据源是默认数据源
	@Primary
	public 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")
	@Primary
	public 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")
	// 表示这个数据源是默认数据源
	@Primary
	public SqlSessionTemplate test1sqlsessiontemplate(
			@Qualifier("数据库标识2SqlSessionFactory") SqlSessionFactory sessionfactory) {
		return new SqlSessionTemplate(sessionfactory);
	}
}


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

spring:
  profiles: 
    active: dev
  mvc: 
    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=false
      username: XXX
      password: XXX
      maxActive: 50
      initialSize: 10
      maxWait: 60000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      maxOpenPreparedStatements: 2
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      filters: stat
      validationQuery: select version()
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
#数据库标识2数据源配置
    数据库标识2:
      jdbc-url: jdbc:oracle:thin:@ip:1521:XXX
      username: XXX
      password: XXX
      maxActive: 50
      initialSize: 5
      maxWait: 60000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      maxOpenPreparedStatements: 2
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: oracle.jdbc.OracleDriver
      filters: stat
      validationQuery: select * from dual
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: 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
     */
    @Bean
    public 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 事务正常回滚

@Transactional
	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;
	}

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 事务没有回滚

@Transactional
	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;
	}

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 事务没有回滚

@Transactional
	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());
		}
	}

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 事务未回滚

@Transactional
	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());
		}
	}

case11 事务回滚

@Transactional(rollbackFor = Exception.class)
	public int testSave() throws Exception {
		return testSave2();
	}
	@Transactional
	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());
		}
	}

case12 事务未回滚

@Transactional(rollbackFor = Exception.class)
	public int testSave() throws Exception {
		return testSave2();
	}
	@Transactional
	public 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;
	}
	@Transactional
	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;
	}

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.OracleDriver
      url: jdbc:oracle:thin:XXX:orcl_tjh
      username: XX
      password: XX
      validation-query: SELECT 1 FROM DUAL
	slave2: 
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/XXX?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
      username: XXXX
      password: XXXX
  1. 在项目中使用,dynamic 配置的都是子数据源。
    在访问的service 方法上 使用@DataSource(数据源表示);如上的slave1

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/71414.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

桥接模式-java实现

桥接模式 桥接模式的本质&#xff0c;是解决一个基类&#xff0c;存在多个扩展维度的的问题。 比如一个图形基类&#xff0c;从颜色方面扩展和从形状上扩展&#xff0c;我们都需要这两个维度进行扩展&#xff0c;这就意味着&#xff0c;我们需要创建一个图形子类的同时&#x…

软件测试基础篇——MySQL

MySQL 1、数据库技术概述 数据库database&#xff1a;存放和管理各种数据的仓库&#xff0c;操作的对象主要是【数据data】&#xff0c;科学的组织和存储数据&#xff0c;高效的获取和处理数据SQL&#xff1a;结构化查询语言&#xff0c;专为**关系型数据库而建立的操作语言&…

科技云报道:一波未平一波又起?AI大模型再出邪恶攻击工具

AI大模型的快速向前奔跑&#xff0c;让我们见识到了AI的无限可能&#xff0c;但也展示了AI在虚假信息、深度伪造和网络攻击方面的潜在威胁。 据安全分析平台Netenrich报道&#xff0c;近日&#xff0c;一款名为FraudGPT的AI工具近期在暗网上流通&#xff0c;并被犯罪分子用于编…

基于微信小程序的应届大学生招聘平台的设计与实现

伴随着社会以及科学技术的发展&#xff0c;互联网已经渗透在人们的身边&#xff0c;网络慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着众多智能手机飞速的发展&#xff0c;小程序这一名词已不陌生&#xff0c;越来越多的企业、公司、高校、医院等机构都会使用小程…

C++学习笔记——从面试题出发学习C++

C学习笔记——从面试题出发学习C C学习笔记——从面试题出发学习C1. 成员函数的重写、重载和隐藏的区别&#xff1f;2. 构造函数可以是虚函数吗&#xff1f;内联函数可以是虚函数吗&#xff1f;析构函数为什么一定要是虚函数&#xff1f;3. 解释左值/右值、左值/右值引用、std:…

Clickhouse学习系列——一条SQL完成gourp by分组与不分组数值计算

笔者在近一两年接触了Clickhouse数据库&#xff0c;在项目中也进行了一些实践&#xff0c;但一直都没有一些技术文章的沉淀&#xff0c;近期打算做个系列&#xff0c;通过一些具体的场景将Clickhouse的用法进行沉淀和分享&#xff0c;供大家参考。 首先我们假设一个Clickhouse数…

EXPLAIN使用分析

系列文章目录 文章目录 系列文章目录一、type说明二、MySQL中使用Show Profile1.查看当前profiling配置2.在会话级别修改profiling配置3.查看profile记录4.要深入查看某条查询执行时间的分布 一、type说明 我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引&…

单参数构造函数的隐式类型转化

单参数构造函数的隐式类型转化 如果你不想发生隐式类型的转化&#xff0c;可以在默认构造函数前加上关键字&#xff1a;explicit 多参数的玩法和单参数的是不一样的 c98 不支持多参数隐式类型的转化 c11 支持多参数隐式类型的转化 举个例子&#xff1a; 多参数可以这样写&…

考虑分布式电源的配电网无功优化问题研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

计算机视觉中的Transformer

几十年来&#xff0c;理论物理学家一直在努力提出一个宏大的统一理论。通过统一&#xff0c;指的是将被认为是完全不同的两个或多个想法结合起来&#xff0c;将它们的不同方面证明为同一基础现象。一个例子是在19世纪之前&#xff0c;电和磁被看作是无关的现象&#xff0c;但电…

SolidWorks不能使用选择如允许此选择将生成有冲突的前后关系

SolidWorks不能使用选择如允许此选择将生成有冲突的前后关系 1 SolidWorks不能使用选择如允许此选择将生成有冲突的前后关系 1 SolidWorks不能使用选择如允许此选择将生成有冲突的前后关系 https://www.swrjzxw.com/1556.html SolidWorks装配体时 显示 不能使用选择如允许此选…

CSS 中的优先级规则是怎样的?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐内联样式&#xff08;Inline Styles&#xff09;⭐ID 选择器&#xff08;ID Selectors&#xff09;⭐类选择器、属性选择器和伪类选择器&#xff08;Class, Attribute, and Pseudo-class Selectors&#xff09;⭐元素选择器和伪元素选择器…

2023.8.12号论文阅读

文章目录 TriFormer: A Multi-modal Transformer Framework For Mild Cognitive Impairment Conversion Prediction摘要本文方法实验结果 SwIPE: Efficient and Robust Medical Image Segmentation with Implicit Patch Embeddings摘要本文方法实验结果 TriFormer: A Multi-mod…

服务器安装Tomcat

下载Tomcat 下载地址在这&#xff1a; Tomcat官网 下载完成以后把压缩包上传到服务器中&#xff08;我传到了www/java&#xff09;,进行解压(解压到)&#xff0c;如果没有进行指定解压到哪里&#xff0c;默认是到root文件夹中 tar -zxvf /www/java/apache-tomcat-9.0.103.tar.…

掌握Python的X篇_32_使用python编辑pdf文件_pdfrw

本篇介绍利用python操作pdf文件&#xff0c;我们平时也会有合并和拆分pdf的需求&#xff0c;此时我们就可以使用本节内容。 文章目录 1. pdfrw的安装2. 切分pdf文件3. pdfrw官网及实现一版四面的实例 1. pdfrw的安装 pip install pdfrw官网地址&#xff1a;https://github.co…

QT之UDP通信

QT之UDP通信 UDP不分客户端口服务器,只需要使用一个类QUdpSocket QT += core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = udp TEMPLATE = app# The following define makes your compiler emit warnings if you use # any feature of Qt …

使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览

使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览 预览方案使用第三方服务使用前端库转换格式 jodconverterjodconverter概述主要特性OpenOfficeLibreOffice jodconverter的基本使用添加依赖配置创建DocumentConverter实例上传与转换预览启动上传与预览World 与Spri…

C#应用处理传入参数 - 开源研究系列文章

今天介绍关于C#的程序传入参数的处理例子。 程序的传入参数应用比较普遍&#xff0c;特别是一个随操作系统启动的程序&#xff0c;需要设置程序启动的时候不显示主窗体&#xff0c;而是在后台运行&#xff0c;于是就有了传入参数问题&#xff0c;比如传入/h或者/min等等。所以此…

配置vscode

配置vscode 设置相关 网址&#xff1a;https://code.visualstudio.com/ 搜索不要用百度用这个&#xff1a;cn.bing.com 1.安装中文包 Chinese (Simplified) (简体中文) 2.安装 open in browser 3.安装主题 Atom One Dark Theme 4. 安装图标样式 VSCode Great Icons 5.安装 L…

25. K 个一组翻转链表

25. K 个一组翻转链表 题目-困难难度示例1. 链表转列表 -> 计算 -> 列表转链表2. 反转合并 题目-困难难度 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果…