有一段时间没写过博客了,最近研究Kotlin,听说优雅,简洁,高效,正好需要写个微信公众号,顺带手就把Kotlin学习了。
本章要点:
一、简单介绍
本次要用的技术主要是最新的组合SpringBoot+MySQL+JPA+Redis+Kotlin+Maven,打算全代码使用Kotlin来实现,主要使用的组件如下:
- SpringBoot,1.5.9.RELEASE
- Spring,4.3.13.RELEASE
- Spring Security,4.3.13.RELEASE
- MySQL,5.0+
- Maven,3.3.X
开发IDE使用IDEA 2017.3,IDEA是Kotlin的创始者,开发Kotlin必然使用IDEA,虽然我比较习惯Eclipse。
二、搭建基本环境
环境搭建其实非常简单,使用IDEA的向导,就能很容易的创建一个Kotlin+maven的项目,怎么搞?移步到这里。
三、编写代码逻辑
首先,我们先看下Maven的配置文件
<?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>com.fncity.mp</groupId>
<artifactId>fix</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>fix</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.10</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
这里有一点需要注意,在Resource节点中,加上了
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
这段配置,通过对Parent POM的观察,发现Resource中application.xml,application.yml等配置文件被excludes掉了,导致在打包的时候,配置文件没有被打入,部署时会抛找不到配置文件的错误。
上面的配置其实是由IDEA自动生成的,后面我们在对其进行个性化配置。
最终的目录结构是这样的:
对于公众号的验证,官方已经给了算法,只要将算法翻译成Kotlin即可。
首先新建一个Kotlin Class,名为Signature,其实我把它当做一个工具类。内容如下:
package com.fncity.mp.core
import com.fncity.common.core.utils.HashUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class Signature {
private val logger: Logger = LoggerFactory.getLogger(Signature::class.java)
// 将Token放到一个map中,以后需要从数据库中获取
private var tokenMap = mapOf(pair = "fix" to "********************")
fun checkSignature(signature: String, timestamp: String, nonce: String, type: String): Boolean {
// 从参数中获取type,并在Map中得到token
val token: String = tokenMap[type].toString()
// 将参数放入一个数组中
val arr: Array<String> = arrayOf(token, timestamp, nonce)
// 将数组进行排序
arr.sort()
// 再将排序好的数据依次拼接成一个字符串
val content = StringBuilder()
for (str: String in arr) {
content.append(str)
}
logger.debug(content.toString())
// 将字符串进行SHA-1加密,得出结果
val result = HashUtils.sha1(content.toString())
logger.debug("Result String:" + result)
logger.debug("Result:" + result.equals(signature.toUpperCase(), false))
// 将结果与传进来的签名进行比对,并返回结果
return result.equals(signature.toUpperCase(), false)
}
}
以上代码很简单,就是将签名算法翻译成程序。附SHA-1的算法:
package com.fncity.common.core.utils
import java.security.MessageDigest
object HashUtils {
fun sha512(input: String) = hashString("SHA-512", input)
fun sha256(input: String) = hashString("SHA-256", input)
fun sha1(input: String) = hashString("SHA-1", input)
private fun hashString(type: String, input: String): String {
val HEX_CHARS = "0123456789ABCDEF"
val bytes = MessageDigest
.getInstance(type)
.digest(input.toByteArray())
val result = StringBuilder(bytes.size * 2)
bytes.forEach {
val i = it.toInt()
result.append(HEX_CHARS[i shr 4 and 0x0f])
result.append(HEX_CHARS[i and 0x0f])
}
return result.toString()
}
}
此算法代码是Google出来某位老外的,感觉相对比较简洁。转自此地址
接下来,当然是写Controller了,我给他命名为:SignatureController,代码如下:
package com.fncity.mp.core
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.*
@RestController
@ResponseBody
open class SignatureController {
private var logger: Logger = LoggerFactory.getLogger(SignatureController::class.java)
@GetMapping("/tokenSign/{type}")
open fun sign(@PathVariable type: String,
@RequestParam signature: String,
@RequestParam nonce: String,
@RequestParam timestamp: String,
@RequestParam echostr: String): String {
val valid = Signature().checkSignature(signature, timestamp, nonce, type)
when (valid) {
true -> return echostr
}
logger.error("Signature invalid!")
return ""
}
}
很简单,调用一下签名算法,如果是true,将echostr返回就可以了,否则就返回个空字符串。
验证部分就到这,简单,就这么简单,不明白的同学请先学习下Kotlin和SpringBoot的基本知识。
后面可能会更新关于JPA的相关内容。