SpringBoot重要组件是各种Starter,需要定制扩展SpringBoot功能,必须自定义Starter。本例自定义Starter只使用与SpringBoot 2.x以后版本,实现Redis缓存管理,文件上传基本服务,使用JDBC操作数据库。
定义Maven工程,定义POM依赖
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gufang</groupId>
<artifactId>mystarter-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mystarter-spring-boot-starter</name>
<url>http://maven.apache.org</url>
<properties>
<!-- project -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<!-- dependencies -->
<spring-boot.version>1.5.10.RELEASE</spring-boot.version>
<!-- plugins -->
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.20.1</maven-surefire-plugin.version>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.0.0</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
定义配置文件操作类
本例重用了SpringBoot-data-jdbc-starter配置信息
package com.gufang;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix="spring.datasource")
public class MyStarterProperties {
private String driverClassName = null;
private String url = null;
private String username = null;
private String password = null;
private String redishost=null;
private String redisport=null;
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRedishost() {
return redishost;
}
public void setRedishost(String redishost) {
this.redishost = redishost;
}
public String getRedisport() {
return redisport;
}
public void setRedisport(String redisport) {
this.redisport = redisport;
}
}
使能注解
package com.gufang;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableMyStarterConfiguration {
}
自配置类
package com.gufang;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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 //向Spring容器配置对象
@ConditionalOnBean(annotation=EnableMyStarterConfiguration.class)
//当Spring容器中包含EnableMyStarterConfiguration声明对象时,进行配置MyStarterAutoConfiguration
@EnableConfigurationProperties(MyStarterProperties.class)
@ServletComponentScan
@EnableCaching
public class MyStarterAutoConfiguration {
@Autowired
private MyStarterProperties prop;
@Bean
public MyConnection createConnecton()
{
String className=prop.getDriverClassName();
String user=prop.getUsername();
String pwd=prop.getPassword();
String url=prop.getUrl();
String redishost=prop.getRedishost();
String redisport=prop.getRedisport();
return new MyConnection(className,url,user,pwd,redishost,redisport);
}
/**
* 生成Redis的键值,根据类名+方法名+参数值的形式
* @return
*/
@Bean(name = "keyGenerator")
public KeyGenerator keyGenerator() {
return new KeyGenerator(){
@Override
public Object generate(Object target, java.lang.reflect.Method method,
Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for(Object obj:params){
if(obj != null)
{
sb.append("_");
sb.append(obj.toString());
}
}
return sb.toString();
}
};
}
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 设置缓存有效期
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(100000000000L));
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
@Bean
@SuppressWarnings({"rawtypes", "unchecked"})
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<Object,Object>();
redisTemplate.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer替换默认的序列化规则
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的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//设置key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
// /**
// * 生成CacheManager对象
// * @param redisTemplate
// * @return
// */
// @Bean
// public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
// RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// cacheManager.setDefaultExpiration(10000);
// return cacheManager;
// }
//
// /**
// * 生成Redis内存管理模板,注解@Primary代表此对象是同类型对象的主对象,优先被使用
// * @param factory
// * @return
// */
// @Primary
// @Bean
// public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
// RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// template.setKeySerializer(new StringRedisSerializer());
// template.setConnectionFactory(factory);
// setSerializer(template);
// template.afterPropertiesSet();
// return template;
// }
/**
* 序列化Redis的键和值对象
* @param template
*/
private void setSerializer(RedisTemplate template){
@SuppressWarnings({ "rawtypes", "unchecked" })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
}
@Bean
public MyRedisTool createRedisTool()
{
return new MyRedisTool();
}
@Bean
public MyFileTool createFileTool()
{
return new MyFileTool();
}
}
数据库操作类
package com.gufang;
import java.sql.Statement;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.gufang.model.FileInfo;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class MyConnection {
private String className,url,user,pwd,redishost,redisport = null;
public MyConnection(String className,String url,String user,String pwd,
String redishost,String redisport)
{
this.className= className;
this.url= url;
this.user= user;
this.pwd= pwd;
this.redishost=redishost;
this.redisport=redisport;
//检查数据库表T_FILE是否存在
createFileTable();
}
public Connection getConnection()
{
try {
Class.forName(className);
return DriverManager.getConnection(url, user, pwd);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<Map> query(String sql)
{
try {
Connection conn=getConnection();
Statement statement=conn.createStatement();
ResultSet rs=statement.executeQuery(sql);
java.sql.ResultSetMetaData rsmData=rs.getMetaData();
List<Map> lst=new ArrayList<Map>();
while(rs.next())//结果集指针
{
int cols=rsmData.getColumnCount();
Map map=new HashMap();
for(int i=1;i<=cols;i++)
{
String colName=rsmData.getColumnName(i);
String val=rs.getString(colName);
map.put(colName, val);
}
lst.add(map);
}
rs.close();
statement.close();
conn.close();
return lst;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void createFileTable()
{
try {
Connection conn=getConnection();
Statement statement=conn.createStatement();
String checkSql = "select id from T_FILE";
try {
statement.execute(checkSql);
System.out.println("######################################################");
System.out.println("###数据库表 T_FILE已经存在 ###");
System.out.println("######################################################");
} catch (Exception e) {
String createSql = "create table T_FILE(id long,"+
"name varchar(200),contexttype varchar(100),length bigint,dt date,content mediumblob)";
statement.execute(createSql);
System.out.println("######################################################");
System.out.println("###数据库表 T_FILE被创建 ###");
System.out.println("######################################################");
}
statement.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void saveFileInfo(FileInfo fi)
{
try {
Connection conn=getConnection();
String sql = "insert into T_FILE(id,name,contexttype,length,dt,content)"+
"values(?,?,?,?,?,?)";
PreparedStatement pstat = conn.prepareStatement(sql);
long id = System.currentTimeMillis();
fi.setId(id);
pstat.setLong(1, fi.getId());
pstat.setString(2, fi.getName());
pstat.setString(3, fi.getContextType());
pstat.setLong(4, fi.getLength());
pstat.setDate(5, new Date(System.currentTimeMillis()));
Blob blob = conn.createBlob();
OutputStream out = blob.setBinaryStream(1);
out.write(fi.getContent());
out.close();
pstat.setBlob(6, blob);
pstat.executeUpdate();
pstat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public FileInfo getFileInfoById(Long id)
{
try {
FileInfo fi = new FileInfo();
Connection conn=getConnection();
String sql = "select * from T_FILE where id=?";
PreparedStatement pstat = conn.prepareStatement(sql);
pstat.setLong(1, id);
ResultSet rs = pstat.executeQuery();
if(rs.next())
{
fi.setId(id);
fi.setName(rs.getString("name"));
fi.setContextType(rs.getString("contexttype"));
fi.setDt(rs.getDate("dt"));
fi.setLength(rs.getLong("length"));
Blob blob = rs.getBlob("content") ;
InputStream input = blob.getBinaryStream();
byte[] data = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int pos = 0;
while((pos=input.read(data))!=-1)
baos.write(data,0,pos);
fi.setContent(baos.toByteArray());
}
pstat.close();
conn.close();
return fi;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
文件操作类
package com.gufang;
import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.gufang.model.FileInfo;
public class MyFileTool {
@Autowired
private MyConnection conn;
public FileInfo uploadFile(HttpServletRequest req)
{
if(!(req instanceof MultipartHttpServletRequest))
return null;
MultipartHttpServletRequest mreq = (MultipartHttpServletRequest)req;
MultipartFile multipartFile = mreq.getFile("file");
try
{
InputStream is = multipartFile.getInputStream();
byte[] bytes = FileCopyUtils.copyToByteArray(is);
FileInfo fi = new FileInfo();
fi.setName(multipartFile.getName());
fi.setContextType(multipartFile.getContentType());
fi.setLength(new Long(multipartFile.getBytes().length));
fi.setContent(bytes);
conn.saveFileInfo(fi);
return fi;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
其他类通过源码下载
https://pan.baidu.com/s/1BUs_3qT1XaS64Y3w3iCZRg
项目中使用自定义Starter
通过注解方式使用Redis
修改Application.properties配置文件
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
#spring.redis.timeout=0
文件上传