spring-boot-starter的理解和开发

Spring Boot Starter 理解

可以认为starter是一种服务(和JS的插件类似)——使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息,由Spring Boot自动通过classpath路径下的类发现需要的Bean,并织入bean

starter 开始

  • 首先创建一个maven项目
  • 项目命名方式为[name]-spring-boot-starter (官方命名方式 spring-boot-starter-[name])
  • 在pom.xml中添加starter所需要的依赖
  • 创建starter相关类(至少有一个自动配置类)
  • 在resource文件夹下创建META-INF文件夹 (srping.factories)

jwt-spring-boot-starter 定义

  • 相关配置的用实体类表示(属性配置类)
  • 开放的服务类
  • JWT工具类
  • 自动配置类
1:创建项目
项目创建

项目命名
2:创建所需要的文件
所需文件

配置文件
3: 代码简介
JwtServiceProperties 属性配置类
// 需要在配置文件配置所需要的属性
// 本例的配置文件
jwt.base64Security = 0914234854!wa
jwt.issuer = alienlabManage

package com.alienlab.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * Created by Msater Zg on 2017/7/13.
 */
 // 读取配置文件,采用的是实体类的方式
 当然你也可以 ${} 的方式
@ConfigurationProperties(prefix = "jwt")
public class JwtServiceProperties {

    /**
     * 密钥
     * 系统的简称
     */
    // 名称要与配置文件相同
    private String base64Security;

    private String issuer;

    public String getBase64Security() {
        return base64Security;
    }

    public void setBase64Security(String base64Security) {
        this.base64Security = base64Security;
    }

    public String getIssuer() {
        return issuer;
    }

    public void setIssuer(String issuer) {
        this.issuer = issuer;
    }
}

JwtService 启动器服务类
// 服务类 开放出来的接口,当然没有接口开放也可以不需要这个类
package com.alienlab.starter;

import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * Created by Msater Zg on 2017/7/13.
 */
public class JwtService {
    // 需要在自动配置类中注入此bean
    @Autowired   
    JwtUtils jwtUtils;

    private String base64Security;

    private String issuer;

    public JwtService(String base64Security, String issuer) {
        this.base64Security = base64Security;
        this.issuer = issuer;
    }

    // 创建 map中放个人信息,可以被他们获取到,第二个是发送给谁,第三参数是过期时间
    public String createPersonToken(Map map, String audience, long TTLMillis) {
        String personToken = jwtUtils.createJWT(map, audience, this.issuer, TTLMillis, this.base64Security);
        return personToken;
    }

    // token
    public Claims parsePersonJWT(String personToken) {
        Claims claims = jwtUtils.parseJWT(personToken, this.base64Security);
        return claims;
    }
}

JwtUtils 工具类(启动器的逻辑类)
// jwt工具类 这个主要是jwt业务逻辑的类,不同的starter业务逻辑肯定是不同的
package com.alienlab.starter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.Map;

/**
 * Created by Msater Zg on 2017/3/13.  jwt实现方式
 */
public class JwtUtils {

    // 加密方法
    public Claims parseJWT(String jsonWebToken, String base64Security) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
                    .parseClaimsJws(jsonWebToken).getBody();
            return claims;
        } catch (Exception ex) {
            return null;
        }
    }

    // 解密方法
    public String createJWT(Map map,
                            String audience, String issuer, long TTLMillis, String base64Security) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        //生成签名密钥 就是一个base64加密后的字符串?
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        //添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
                .setIssuedAt(now)  //创建时间
                .setSubject(map.toString()) //主题,也差不多是个人的一些信息
                .setIssuer(issuer) //发送谁
                .setAudience(audience) //个人签名
                .signWith(signatureAlgorithm, signingKey);  //估计是第三段密钥
        //添加Token过期时间
        if (TTLMillis >= 0) {
            // 过期时间
            long expMillis = nowMillis + TTLMillis;
            // 现在是什么时间
            Date exp = new Date(expMillis);
            // 系统时间之前的token都是不可以被承认的
            builder.setExpiration(exp).setNotBefore(now);
        }
        //生成JWT
        return builder.compact();
    }
}

JwtAutoConfiguration 自动装配类(必须的文件类)
// 自动装配类(最重要的类,没有此类,spring boot不会自动扫描jar)
package com.alienlab.starter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by Msater Zg on 2017/7/13.
 */
@Configuration
@ConditionalOnClass(JwtService.class)
@EnableConfigurationProperties(JwtServiceProperties.class)
public class JwtAutoConfiguration {
    @Autowired
    private JwtServiceProperties jwtServiceProperties;

    // 创建相关bean
    @Bean
    JwtService jwtService() {
        return new JwtService(jwtServiceProperties.getBase64Security(), jwtServiceProperties.getIssuer());
    }

    @Bean
    JwtUtils jwtUtils() {
        return new JwtUtils();
    }
}

//创建bean 的一些判断条件注解
@Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "jwt",value ="enabled",havingValue = "true")
    JwtUtils jwtUtils() {
        return new JwtUtils();
    }
    
@ConditionalOnClass,当classpath下发现该类的情况下进行自动配置。
@ConditionalOnMissingBean,当Spring Context中不存在该Bean时。
@ConditionalOnProperty(prefix = "jwt",value = "enabled",havingValue = "true"),jwt.enabled=true时

spring.factories文件(必需的,这样spring boot启动时,才会发现并且加载这个jar)
// 指向刚才自动装配类路径
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alienlab.starter.JwtAutoConfiguration
4:pom.xml文件详情(所依赖的jar,如果不同启动器所依赖的jar有相同,则尽量写在一起。防止两个同时引用产生jar包冲突的问题!)
<?xml version="1.0" encoding="UTF-8"?>
<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>alienlab</groupId>
    <artifactId>jwt-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <jwtio.version>0.6.0</jwtio.version>
        <auth0.version>3.1.0</auth0.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>${auth0.version}</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwtio.version}</version>
        </dependency>
    </dependencies>

</project>
4:项目打包
  • 到项目的pom.xml文件所在的同一层级目录,打开命令窗口输入命令 mvn install ,打包好的starter在项目的target目录里面。
5: 开始使用(创建好spring boot项目)
// 添加依赖(选择自己的启动器路径)
<dependency>
       <groupId>alienlab</groupId>
       <artifactId>jwt-spring-boot-starter</artifactId>
       <version>1.0-SNAPSHOT</version>
 </dependency>
//在application.properties配置所需要的属性
#jwt setting
jwt.base64Security=091418wa!
jwt.issuer=yuqingmanage

//自动注入,并开始使用服务的方法
@Autowired
    JwtService jwtService;
    
@RequestMapping(value = "/getAllSysUser", method = RequestMethod.GET)
    @ApiOperation(value = "getAllSysUser", notes = "获取到所有的用户")
    @ApiImplicitParams({
    })
    public String getAllSysUser() {
        String reuslt = iUserService.getAllSysUser().toString();
        Map map = new HashMap();
        map.put("user", "赵刚");
        System.out.println(jwtService.createPersonToken(map, "1402753117", 200));
        return reuslt;
    }
结语:
  • 后续的项目直接引入依赖,不需要重新复制。代码维护非常方便,将自己的starter上传到maven仓库其他人就可以下载使用。当然starter并不是万能的,适用于一些和系统的业务没有直接关联的逻辑。比如swagger,跨域的配置,拦截器,jwt安全加密,缓存等等!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容