我用SpringBoot(Kotlin)和Freemarker制作了一个登录示例
因为工作需要,我开始使用SpringBoot和FreeMarker,尝试实现一个简单的登录页面。
另外,由于似乎要在前端使用Vue,所以顺便尝试将Webpack和Gradle整合起来,实现加载Vue。
由于SpringBoot的Kotlin仍然缺乏日语文档,因此我将在说明过程中附上源码,并简要概括要点。
源代码
https://github.com/renoinn/springboot-freemarker-vue-sample
只要在Docker或类似平台上准备好数据库,应该就可以直接运行。
构建.gradle
buildscript {
ext {
kotlinVersion = '1.2.51'
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
classpath "com.moowork.gradle:gradle-node-plugin:1.2.0"
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'kotlin-allopen'
apply plugin: 'kotlin-jpa'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'com.moowork.node'
group = 'com.sample'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
repositories {
mavenCentral()
}
dependencies {
// spring
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-freemarker')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.session:spring-session-core')
runtime('org.springframework.boot:spring-boot-devtools')
compileOnly "org.springframework.boot:spring-boot-configuration-processor"
// etc
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile('no.api.freemarker:freemarker-java8:1.2.0')
// mysql
runtime('mysql:mysql-connector-java')
// test
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
}
node {
version = '9.11.2'
npmVersion = '6.4.1'
download = true
}
// Webpackでのビルドを実行するタスク
task webpack(type: NodeTask, dependsOn: 'npmInstall') {
def osName = System.getProperty("os.name").toLowerCase()
if (osName.contains("windows")) {
script = project.file('node_modules/webpack/bin/webpack.js')
} else {
script = project.file('node_modules/.bin/webpack')
}
}
// processResourcesタスクの前に上述のwebpackタスクを実行する
processResources.dependsOn 'webpack'
clean.delete << file('node_modules')
首先是build.gradle。在使用Kotlin进行Spring Boot开发时,kotlin-allopen、kotlin-noarg和kotlin-jpa可以帮助简化一些稍微繁琐的部分。
另外,为了与webpack进行协同,也需要添加gradle-node-plugin。
WebSecurityConfig.kt 的中文释义。
@Configuration
@EnableWebSecurity
class WebSecurityConfig : WebSecurityConfigurerAdapter() {
@Override
@Throws(Exception::class)
override fun configure(web: WebSecurity) {
// これらにマッチするURLへのアクセスは無視する
web.ignoring().antMatchers(
"/images/**",
"/css/**",
"/js/**",
"/webjars/**")
}
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.csrf().disable()
http.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin() // フォームでのログインをする宣言
.loginProcessingUrl("/login") // ログイン処理をするエンドポイント。formのactionでここを指定する
.loginPage("/") // ログインフォームのURL
.defaultSuccessUrl("/home") // ログイン成功後のURL
http.logout()
.logoutRequestMatcher(AntPathRequestMatcher("/logout**")) // マッチするリクエストがきたらログアウトする
.logoutSuccessUrl("/") // ログアウト後のURL
}
@Configuration
class AuthenticationConfiguration : GlobalAuthenticationConfigurerAdapter() {
@Autowired
var userDetailsService: UserDetailsServiceImpl = UserDetailsServiceImpl()
@Throws(Exception::class)
override fun init(auth: AuthenticationManagerBuilder) {
auth.userDetailsService<UserDetailsService>(userDetailsService)
.passwordEncoder(BCryptPasswordEncoder())
}
}
}
接下来是针对Spring Security的配置。通过覆盖WebSecurityConfigurerAdapter内的configure方法来添加设置。
还有一部分,覆盖了GlobalAuthenticationConfigurerAdapter内的init方法。需要将PasswordEncoder传递给AuthenticationManagerBuilder才能启用Spring Security,所以要注意。即使是以明文保存密码的情况,也必须使用NoOpPasswordEncoder进行传递。我认为几乎不会使用明文保存密码这样的情况。
在使用Spring Security时,需要准备一个继承UserDetails的实体类和实现UserDetailsService接口的实现类。
User.kt = 用户.kt
UserDetailsServiceImpl.kt文件
@Service
class UserDetailsServiceImpl : UserDetailsService {
@Autowired
lateinit var userRepository: UserRepository
override fun loadUserByUsername(username: String): UserDetails {
val user = findByUsername(username)
if (!user.isPresent)
throw UsernameNotFoundException("Username $username is not found")
if (!user.get().isAccountNonLocked)
throw UsernameNotFoundException("Username $username is locked")
return user.get().copy(authorities = getAuthorities())
}
private fun getAuthorities() = AuthorityUtils.createAuthorityList("ROLE_USER")
fun findByUsername(username: String): Optional<User> {
val user = userRepository.findByUsername(username)
return user
}
}
只需一个选项,将以下内容用中文进行重述:
只要查看UserDetails实体后,UserDetailsServiceImpl必须重写loadUserByUsername来返回UserDetails。在这种情况下,返回的UserDetails对象的authorities属性值必须以ROLE_前缀开始,比如ROLE_USER或ROLE_ADMIN,注意这一点。
webpack配置文件。
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: './src/main/js/app.js',
output: {
filename: 'js/bundle.js',
path: __dirname + '/build/resources/main/static/'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
}
}
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new ExtractTextPlugin("css/styles.css"),
]
}
;
webpack应该没有做任何特别复杂的事情。将文件放置在/build/resources/main/static/js目录下,就可以通过https://hoge.com/js进行访问,因此output设置为那里。
因为我还在学习阶段,所以非常欢迎像这样的建议性评论和Pull请求。
请提供参考的URL链接。
-
- https://qiita.com/nvtomo1029/items/8827d95327b647a6cf50
-
- https://qiita.com/rykgy/items/2714299253bcc87e0118
-
- https://github.com/tokuhirom/spring-vue-sample
- https://spring.io/guides/tutorials/spring-boot-kotlin/