上传文件服务

社团注册服务
增加图片文件表、社团表、后台管理员表、审核记录表
完善服务抽象类
master
pan 3 years ago
parent 662c6930a0
commit 80468467b0
  1. 1
      build.gradle.kts
  2. 1
      resources/application.conf
  3. 2
      resources/logback.xml
  4. 21
      src/Application.kt
  5. 210
      src/Controller.kt
  6. 108
      src/Dao.kt
  7. 2
      src/MySQL.kt
  8. 281
      src/Service.kt
  9. 25
      src/Util.kt
  10. 20
      src/Vo.kt
  11. 27
      test/ApplicationTest.kt
  12. 32
      test/ChannelTest.kt

@ -29,6 +29,7 @@ dependencies {
*/
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("io.ktor:ktor-server-core:$ktor_version")
/**
* https://github.com/google/gson
*/

@ -11,6 +11,7 @@ ktor {
leaveMessage {
maxSize = 20
}
filePath = upload
watch = [ classes ]
}
application {

@ -1,7 +1,7 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<pattern>%d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level - %C:%L - %msg%n</pattern>
</encoder>
</appender>
<root level="trace">

@ -22,15 +22,26 @@ fun Application.module(testing: Boolean = false) {
}
install(ContentNegotiation) {
gson {
}
gson()
}
install(CallLogging)
}
fun Application.Controller(testing: Boolean = false){
this.AccountController()
this.TestController()
this.MainController()
AccountController()
TestController()
MainController()
AssociationController()
NotificationController()
/**
* 初始化log
*/
listOf(MainService,AccountService,FileService,AssociationService,BackgroundService).forEach {
it.init(environment)
}
}

@ -1,26 +1,26 @@
package com.gyf.csams
import io.ktor.application.*
import io.ktor.http.content.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import org.slf4j.LoggerFactory
import kotlinx.coroutines.channels.Channel
suspend inline fun <reified T:BaseVo> withToken(call:ApplicationCall, callback:(vo:T)->Unit){
val levelVo=call.receive<T>()
if(AccountService.validToken(levelVo.token)){
suspend inline fun <reified T : BaseVo> withToken(call: ApplicationCall, callback: (vo: T) -> Unit) {
val levelVo = call.receive<T>()
if (AccountService.validToken(levelVo.token)) {
callback(levelVo)
}else{
call.respond(ApiResponse(message = "token校验失败",body = null))
} else {
call.respond(Simple.error("token校验失败"))
}
}
private val logger = LoggerFactory.getLogger(Application::class.java)
fun Application.AccountController() {
routing {
route(path = "$ApiPathPrefix/account"){
route(path="/register") {
route(path = "$ApiPathPrefix/account") {
route(path = "/register") {
/**
* 检测学号是否已注册
*/
@ -41,37 +41,37 @@ fun Application.AccountController() {
* 注册账号
*/
post {
val userVo = call.receive<UserVo>()
val userResDto = AccountService.register(userVo)
if (userResDto != null) {
call.respond(ApiResponse(message = "注册成功", body = userResDto))
} else {
call.respond(Simple.error("注册失败"))
}
val userVo = call.receive<UserVo>()
val userResDto = AccountService.register(userVo)
if (userResDto != null) {
call.respond(ApiResponse(message = "注册成功", body = userResDto))
} else {
call.respond(Simple.error("注册失败"))
}
}
}
route(path = "/login"){
post{
val userLoginVo= call.receive<UserLoginVo>()
logger.info("执行登陆")
val token=AccountService.login(userLoginVo,call.request.host())
logger.info("登录请求处理完毕")
call.respond(ApiResponse(message = if(token!=null) "登陆成功" else "账号或密码错误!!!",body = token))
route(path = "/login") {
post {
val userLoginVo = call.receive<UserLoginVo>()
environment.log.info("执行登陆")
val token = AccountService.login(userLoginVo, call.request.host())
environment.log.info("登录请求处理完毕")
call.respond(ApiResponse(message = if (token != null) "登陆成功" else "账号或密码错误!!!", body = token))
}
post(path = "/token"){
val tokenVo=call.receive<TokenVo>()
val isValid=AccountService.validToken(tokenVo)
call.respond(ApiResponse(message = if(isValid) "令牌合法" else "令牌不合法",body = isValid))
post(path = "/token") {
val tokenVo = call.receive<TokenVo>()
val isValid = AccountService.validToken(tokenVo)
call.respond(ApiResponse(message = if (isValid) "令牌合法" else "令牌不合法", body = isValid))
}
}
post(path = "/logout"){
logger.info("退出登录")
val userLogoutVo=call.receive<UserLogoutVo>()
logger.info("$userLogoutVo")
val flag=AccountService.logout(userLogoutVo.studentId)
call.respond(ApiResponse(message = if(flag) "退出成功" else "退出失败",body = flag))
post(path = "/logout") {
environment.log.info("退出登录")
val userLogoutVo = call.receive<UserLogoutVo>()
environment.log.info("$userLogoutVo")
val flag = AccountService.logout(userLogoutVo.userId)
call.respond(ApiResponse(message = if (flag) "退出成功" else "退出失败", body = flag))
}
}
}
@ -81,33 +81,153 @@ fun Application.AccountController() {
* 主界面接口
*
*/
fun Application.MainController(){
MainService.register(maxSize = environment.config.property("ktor.deployment.leaveMessage.maxSize").getString().toInt())
fun Application.MainController() {
routing {
//发送留言
route("$ApiPathPrefix/main") {
post("/leaveMessage") {
withToken<LeaveMessageVo>(call){
val flag=MainService.createMessage(leaveMessageVo = it)
call.respond(ApiResponse(message = if(flag) "留言创建成功" else "留言创建失败",body=flag))
withToken<LeaveMessageVo>(call) {
val flag = MainService.createMessage(leaveMessageVo = it)
call.respond(ApiResponse(message = if (flag) "留言创建成功" else "留言创建失败", body = flag))
}
}
post("/getMessage"){
withToken<OnlyToken>(call){
val s=MainService.getAllLeaveMessage()
call.respond(ApiResponse(message = "留言获取成功",body = s))
post("/getMessage") {
withToken<OnlyToken>(call) {
val s = MainService.getAllLeaveMessage()
call.respond(ApiResponse(message = "留言获取成功", body = s))
}
}
}
}
}
fun Application.TestController(){
fun Application.TestController() {
routing {
get("$ApiPathPrefix/test"){
get("$ApiPathPrefix/test") {
AccountService.test()
call.respond(ApiResponse(message = "成功连接服务端",body=true))
call.respond(ApiResponse(message = "成功连接服务端", body = true))
}
get("$ApiPathPrefix/testR"){
sendNotification(SimpleNotification())
call.respond("建立通知成功")
}
}
}
fun Application.AssociationController() {
routing {
route("$ApiPathPrefix/association") {
post("/uploadLogo") {
val multipartData = call.receiveMultipart()
multipartData.readAllParts().apply {
environment.log.info("part size=$size")
if (size == 3) {
val result=FileService.storeFile(this)
call.respond(ApiResponse(message = if(result.isNullOrEmpty()) "文件上传失败" else
"成功上传${result.size}个文件",body = result))
} else {
call.respond(Simple.error("参数异常"))
throw IllegalArgumentException("参数异常")
}
}
}
post("/register"){
withToken<RegAssociationVo>(call = call){
val flag=AssociationService.register(vo=it)
call.respond(ApiResponse(message = if(flag) "社团注册资料已保存,请等待受理" else "社团注册资料保存失败",body=flag))
}
}
}
}
}
/**
* TODO
*
*/
enum class NotificationType{
System
}
/**
* 通知接收客户端
*
*/
enum class ReceiverType{
//前台
Foreground,
//后台
Background
}
/**
* 通知接收者
*
*/
sealed class Receiver{
protected abstract val id:Int
abstract val target:ReceiverType
}
/**
* 后台客户端接收
*
* @property managerId 管理员id
*/
data class BackgroundReceiver(val managerId:Int,override val id: Int=managerId, override val target: ReceiverType=ReceiverType.Background):Receiver()
/**
* 前台客户端接收
*
* @property userId 用户id
*/
data class ForegroundReceiver(val userId:Int, override val id:Int=userId, override val target: ReceiverType=ReceiverType.Foreground):Receiver()
sealed class NotificationVo{
abstract val type:NotificationType
abstract val title:String
abstract val receiver:Receiver
}
/**
* 系统通知
*
* @property type
* @property title
*/
sealed class SysNotificationVo<T>:NotificationVo(){
override val type: NotificationType=NotificationType.System
abstract val content:T
}
/**
* 注册社团通知
*
* @property title
*/
data class RegisterNotification(override val title: String="注册社团通知", override val content: RegAssociationDto,
override val receiver: ForegroundReceiver
):SysNotificationVo<RegAssociationDto>()
data class SimpleNotification(
override val type: NotificationType=NotificationType.System,
override val title: String="test",
override val receiver: Receiver=BackgroundReceiver(managerId = randomNum().toInt())
):NotificationVo()
private val channel = Channel<NotificationVo>()
suspend fun sendNotification(vo:NotificationVo){
channel.send(vo)
}
fun Application.NotificationController(){
routing {
}
}

@ -33,8 +33,8 @@ class User(id:EntityID<Int>):IntEntity(id){
@TableComment("用户授权令牌")
object UserTokens: IntIdTable(){
@TableComment("授权学号")
val studentId:Column<String> = reference("student_id",Users.studentId)
@TableComment("授权用户")
val userId:Column<EntityID<Int>> = reference("user_id",Users)
@TableComment("令牌")
val token:Column<String> = varchar(name="token",length = 32)
@ -51,7 +51,7 @@ object UserTokens: IntIdTable(){
class UserToken(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<UserToken>(UserTokens)
var studentId by UserTokens.studentId
var user by User referencedOn UserTokens.userId
var token by UserTokens.token
var ip by UserTokens.ip
var createTime by UserTokens.createTime
@ -61,7 +61,7 @@ class UserToken(id:EntityID<Int>):IntEntity(id){
@TableComment("留言")
object LeaveMessages:IntIdTable(){
@TableComment("留言用户")
val studentId:Column<String> = reference("student_id",Users.studentId)
val userId:Column<EntityID<Int>> = reference("user_id",Users)
@TableComment("留言内容")
val message:Column<String> = varchar(name = "message",length = 20)
@ -72,8 +72,106 @@ object LeaveMessages:IntIdTable(){
class LeaveMessage(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<LeaveMessage>(LeaveMessages)
var studentId by LeaveMessages.studentId
var user by User referencedOn LeaveMessages.userId
var message by LeaveMessages.message
var createTime by LeaveMessages.createTime
}
@TableComment("图片文件信息")
object ImageFiles:IntIdTable(){
@TableComment("上传用户")
val userId:Column<String> = varchar(name = "user_id",length = 10)
@TableComment("文件相对路径")
val filepath:Column<String> = varchar(name="filepath",length = 50)
@TableComment("文件hash")
val md5:Column<String> = varchar(name="md5",length = 32)
@TableComment("文件创建时间")
val createTime:Column<LocalDateTime> = datetime("create_time").defaultExpression(CurrentDateTime())
}
class ImageFile(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<ImageFile>(ImageFiles)
var userId by ImageFiles.userId
var filepath by ImageFiles.filepath
var md5 by ImageFiles.md5
var createTime by ImageFiles.createTime
}
@TableComment("社团")
object Associations:IntIdTable(){
@TableComment("社团名称")
val name:Column<String> =varchar(name = "name",length = 10)
@TableComment("社团介绍")
val desc:Column<String> =varchar(name = "desc",length = 30)
@TableComment("社团logo")
val logo:Column<EntityID<Int>> = reference("logo",ImageFiles)
@TableComment("社团审核状态")
val status:Column<Boolean> = bool(name="status").default(false)
}
class Association(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<Association>(Associations)
var name by Associations.name
var desc by Associations.desc
var logo by ImageFile referencedOn Associations.logo
var status by Associations.status
}
@TableComment("后台管理员")
object Managers:IntIdTable(){
@TableComment("帐号")
val account:Column<String> = varchar(name="account",length=10)
@TableComment("密码")
val password:Column<String> = varchar(name="password",length = 32)
@TableComment("职务")
val duty:Column<String> = varchar(name="duty",length = 32)
@TableComment("等级")
val level:Column<Int> = integer("level")
}
class Manager(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<Manager>(Managers)
var account by Managers.account
var password by Managers.password
var duty by Managers.duty
var level by Managers.level
}
@TableComment("审核记录")
object CheckForms:IntIdTable(){
@TableComment("审核类型")
val type:Column<String> = varchar(name="type",length = 10)
@TableComment("审核人")
val managerId:Column<EntityID<Int>> = reference("manager_id",Managers)
@TableComment("审核理由")
val cause:Column<String> = varchar("cause",length = 30)
@TableComment("审核对象")
val target:Column<Int> = integer("target")
@TableComment("审核时间")
val createTime:Column<LocalDateTime> = datetime("create_time").defaultExpression(CurrentDateTime())
}
class CheckForm(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<CheckForm>(CheckForms)
val type by CheckForms.type
val manager by Manager referrersOn CheckForms.managerId
val cause by CheckForms.cause
val target by CheckForms.target
}

@ -40,7 +40,7 @@ fun Application.MySQL(testing: Boolean = false){
fun initTable(){
transaction {
val tableList= arrayOf(Users,UserTokens,LeaveMessages)
val tableList= arrayOf(Users,UserTokens,LeaveMessages,ImageFiles,Associations,Managers,CheckForms)
SchemaUtils.createMissingTablesAndColumns(*tableList)
updateComment(*tableList)

@ -1,13 +1,30 @@
package com.gyf.csams
import io.ktor.application.*
import io.ktor.http.content.*
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
import org.slf4j.Logger
import java.io.File
import java.time.ZoneOffset
import kotlin.properties.Delegates
interface BaseService{
fun init(environment:ApplicationEnvironment)
}
abstract class AbstractService:BaseService{
protected lateinit var log:Logger
override fun init(environment: ApplicationEnvironment) {
this.log=environment.log
}
}
object AccountService {
private val logger = LoggerFactory.getLogger(AccountService::class.java)
/**
* 账号服务
*/
object AccountService:AbstractService() {
/**
* 检查学号是否已注册,true=已注册
*/
@ -23,16 +40,16 @@ object AccountService {
fun register(userVo: UserVo): UserResDto? {
try {
return transaction {
val _pwd = randomNum(8)
val originPassword = randomNum(8)
User.new {
studentId=userVo.studentId
name=userVo.name
password=_pwd.md5()
password=originPassword.md5()
}
return@transaction UserResDto(password=_pwd)
return@transaction UserResDto(password=originPassword)
}
} catch (e: Exception) {
logger.error("注册失败,发生异常:$e")
log.error("注册失败,发生异常:$e")
return null
}
}
@ -44,35 +61,35 @@ object AccountService {
*/
fun login(userLoginVo: UserLoginVo,_ip:String):Token?{
return transaction {
val user=User.find { Users.studentId eq userLoginVo.studentId }.firstOrNull()
val matchUser=User.find { Users.studentId eq userLoginVo.studentId }.firstOrNull()
when {
user==null -> {
logger.warn("学号:${userLoginVo.studentId}不存在")
matchUser==null -> {
log.warn("学号:${userLoginVo.studentId}不存在")
return@transaction null
}
userLoginVo.password.md5() != user.password -> {
logger.warn("密码:${userLoginVo.password}错误")
userLoginVo.password.md5() != matchUser.password -> {
log.warn("密码:${userLoginVo.password}错误")
return@transaction null
}
else -> {
val token=UserToken.new{
studentId=userLoginVo.studentId
user=matchUser
ip=_ip
device=userLoginVo.device
token=listOf(studentId,ip,device).joinToString(separator = ('a' .. 'z').random().toString()).md5()
token=listOf(matchUser.id,ip,device).joinToString(separator = ('a' .. 'z').random().toString()).md5()
}
token.flush()
return@transaction Token(studentId = userLoginVo.studentId,token = token.token,
return@transaction Token(userId = matchUser.id.value,token = token.token,
createTime = token.createTime.toEpochSecond(
ZoneOffset.of("+8")),name=user.name)
ZoneOffset.of("+8")))
}
}
}
}
fun validToken(token: Token):Boolean{
return validToken(TokenVo(token = token.token,studentId = token.studentId))
return validToken(TokenVo(token = token.token,userId = token.userId))
}
/**
@ -84,37 +101,40 @@ object AccountService {
fun validToken(tokenVo: TokenVo):Boolean{
return transaction {
!UserToken.find {
UserTokens.studentId eq tokenVo.studentId
UserTokens.userId eq tokenVo.userId
UserTokens.token eq tokenVo.token
}.empty()
}
}
fun logout(studentId:String):Boolean{
fun logout(userId:Int):Boolean{
return transaction {
UserTokens.deleteWhere { UserTokens.studentId eq studentId }>0
UserTokens.deleteWhere { UserTokens.userId eq userId }>0
}
}
fun test(){
logger.info("开始测试")
log.info("开始测试")
transaction {
logger.info("查询到个${User.count()}用户")
log.info("查询到个${User.count()}用户")
}
logger.info("结束测试")
log.info("结束测试")
}
}
object MainService{
private val logger = LoggerFactory.getLogger(MainService::class.java)
var maxSize:Int=20
/**
* 主页服务
*/
object MainService:AbstractService(){
private var maxSize by Delegates.notNull<Int>()
fun register(maxSize:Int){
this.maxSize=maxSize
override fun init(environment:ApplicationEnvironment){
super.init(environment)
this.maxSize=environment.config.property("ktor.deployment.leaveMessage.maxSize").getString().toInt()
}
/**
* 创建留言信息
*
@ -125,32 +145,219 @@ object MainService{
return if(leaveMessageVo.message.isNotEmpty()){
return transaction {
val count=LeaveMessage.count().toInt()
logger.info("系统留言数:$count,限制数:$maxSize")
log.info("系统留言数:$count,限制数:$maxSize")
if(count>= maxSize){
LeaveMessage.all().sortedBy { it.createTime }.subList(0, count-maxSize).forEach {
it.delete()
}
}
logger.info("保存留言:${leaveMessageVo.message}")
log.info("保存留言:${leaveMessageVo.message}")
LeaveMessage.new {
studentId = leaveMessageVo.token.studentId
user= User.findById(leaveMessageVo.token.userId)?:throw IllegalArgumentException("非法id")
message = leaveMessageVo.message
}
logger.info("留言保存成功")
log.info("留言保存成功")
return@transaction true
}
}else{
logger.info("留言不能为空")
log.info("留言不能为空")
false
}
}
fun getAllLeaveMessage():List<LeaveMessageFormatVo>{
fun getAllLeaveMessage():List<LeaveMessageDto>{
return transaction {
logger.info("获取所有留言")
log.info("获取所有留言")
return@transaction LeaveMessage.all().toList().map {
LeaveMessageFormatVo(message = "${User.find { Users.studentId eq it.studentId }.first().name}说:${it.message}",studentId = it.studentId)
LeaveMessageDto(
message = "${it.user.name}说:${it.message}",
user = UserVo(studentId = it.user.studentId, name = it.user.name)
)
}
}
}
}
/**
* 文件管理服务
*/
object FileService:AbstractService(){
private lateinit var uploadDir:String
private lateinit var filePath:String
override fun init(environment:ApplicationEnvironment){
super.init(environment)
this.uploadDir= environment.config.property("ktor.deployment.filePath").getString()
val resourcePath =this::class.java.classLoader.getResource("")?.path ?: throw IllegalArgumentException("初始化资源目录失败")
File(resourcePath, uploadDir).apply {
when{
!exists()&&mkdir()-> {
log.info("图片上传路径[${absolutePath}]初始化成功")
this@FileService.filePath=absolutePath
}
exists()->{
log.info("图片上传路径[${absolutePath}]已存在")
this@FileService.filePath=absolutePath
}
else->throw IllegalArgumentException("图片上传路径[${absolutePath}]初始化失败")
}
}
}
private fun save(id: String, path:String, file: File):Int{
return transaction {
return@transaction ImageFile.new {
userId = id
filepath = path
md5 = file.readBytes().md5()
}
}.id.value
}
private inline fun <reified T:PartData> getPartData(map:Map<String?, PartData>, key:String):T{
if(map.containsKey(key)){
val obj= map[key]
if(obj is T){
return obj
}else{
throw IllegalArgumentException("类型错误")
}
}
throw IllegalArgumentException("找不到key:${key}")
}
fun storeFile(data:List<PartData>):List<Int>?{
val map=data.associateBy {
it.name
}.toMutableMap()
log.info("map=${map}")
val userId=getPartData<PartData.FormItem>(map,"id").value
val token= getPartData<PartData.FormItem>(map,"token").value
val tokenVo=TokenVo(token=token,userId=userId.toInt())
if(AccountService.validToken(tokenVo)){
map.remove("id")
map.remove("token")
val fileIds= mutableListOf<Int>()
map.forEach{
val value=it.value
if(value is PartData.FileItem){
val fileBytes = value.streamProvider().readBytes()
val fileName=value.originalFileName?:throw IllegalArgumentException("参数异常")
val format = fileBytes.getFormat()
val fullFileName="${fileName}.${format.format}"
log.info("fullFileName=$fullFileName")
val file=File(filePath,fullFileName).apply {
writeBytes(fileBytes)
}
val fileId= save(id = userId,"${uploadDir}/${fullFileName}",file=file)
fileIds.add(fileId)
}
}
return fileIds
}else{
return null
}
}
}
/**
* 社团服务
*/
object AssociationService: AbstractService() {
fun register(vo:RegAssociationVo):Boolean{
return try {
transaction {
Association.new {
name=vo.name
desc=vo.desc
logo=ImageFile.findById(vo.fileId) ?: throw IllegalArgumentException("文件id不存在!")
}
}
log.info("未审核社团创建成功")
true
} catch (e: Exception) {
log.error(e.stackTraceToString())
false
}
}
}
enum class ManagerType(val desc:String,val level:Int){
Teacher("老师",1),
PamphaBhusal("总部长",2),
SecretaryOfTheMinister("秘书部部长",3),
PropagandaDepartment("宣传部部长",3),
LiaisonMinister("外联部部长",3),
SecretaryDepartmentOfficer("秘书部干事",4),
PublicityDepartmentOfficer("宣传部干事",4),
LiaisonOfficer("外联部干事",4)
}
object NotificationService:AbstractService(){
}
/**
* 后台服务
*/
object BackgroundService:AbstractService(){
override fun init(environment: ApplicationEnvironment) {
super.init(environment)
initManager()
}
private fun createManager(type:ManagerType, num:Int=1): MutableList<InitManagerDto> {
val managerList= mutableListOf<InitManagerDto>()
repeat(num){
val originPassword=randomNum()
Manager.new {
account= randomNum()
password = originPassword.md5()
duty=type.name
level=type.level
}.apply {
managerList.add(InitManagerDto(account=account,originPassword=originPassword))
}
}
return managerList
}
//初始化管理员
private fun initManager(){
transaction {
val resourcePath =this::class.java.classLoader.getResource("")?.path ?: throw IllegalArgumentException("初始化资源目录失败")
val file=File(resourcePath,"管理员账号.txt")
if(!file.exists()) {
Manager.count().let { it ->
if (it.toInt() == 0) {
val allManager = mutableListOf<InitManagerDto>()
allManager.addAll(createManager(ManagerType.Teacher, 1))
allManager.addAll(createManager(ManagerType.PamphaBhusal, 1))
allManager.addAll(createManager(ManagerType.SecretaryOfTheMinister, 1))
allManager.addAll(createManager(ManagerType.PropagandaDepartment, 1))
allManager.addAll(createManager(ManagerType.LiaisonMinister, 1))
arrayOf(
ManagerType.SecretaryDepartmentOfficer,
ManagerType.PublicityDepartmentOfficer,
ManagerType.LiaisonOfficer
).forEach {
allManager.addAll(createManager(it, 3))
}
allManager.forEach {
file.appendText("${it.account}------${it.originPassword}\n")
}
log.info("共生成${allManager.size}个管理员账号")
} else {
log.info("不需要生成管理员")
}
}
}
}
}

@ -5,6 +5,7 @@ import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.vendors.MysqlDialect
import org.jetbrains.exposed.sql.vendors.currentDialect
import java.io.File
import java.math.BigInteger
import java.security.MessageDigest
@ -24,9 +25,33 @@ fun String.md5(): String {
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
}
fun ByteArray.md5():String{
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(this)).toString(16).padStart(32, '0')
}
@Target(AnnotationTarget.CLASS,AnnotationTarget.FIELD)
annotation class TableComment(val comment:String)
enum class FileFormat(val format:String,val head:String){
JPEG("jpg","FFD8FF")
}
fun ByteArray.getFormat(): FileFormat = format(this) ?: throw IllegalArgumentException("无法识别数据格式")
fun File.getFormat(): FileFormat {
val bytes=readBytes()
return format(bytes) ?: throw IllegalArgumentException("无非识别文件[${absolutePath}]文件的格式")
}
private fun format(bytes:ByteArray):FileFormat?{
FileFormat.values().forEach { it ->
if(it.head==bytes.copyOf(it.head.length / 2).joinToString(separator = "") { String.format("%02X",it) }){
return it
}
}
return null
}
/**
* 表字段添加注释

@ -1,7 +1,5 @@
package com.gyf.csams
import kotlinx.serialization.Serializable
data class ApiResponse<T>(val code:Int=200,val message:String,val body:T?=null)
@ -23,7 +21,6 @@ class Simple {
* @property studentId 学号
* @property name 姓名
*/
@Serializable
data class UserVo(val studentId:String,val name:String)
/**
@ -35,14 +32,13 @@ data class UserVo(val studentId:String,val name:String)
*/
data class UserLoginVo(val studentId: String,val password: String,val device: String)
@Serializable
data class UserLogoutVo(val studentId:String)
data class UserLogoutVo(val userId:Int)
data class UserResDto(val password:String)
data class Token(val token:String,val createTime:Long,val studentId:String,val name:String)
data class Token(val token:String, val createTime:Long, val userId:Int)
data class TokenVo(val token:String,val studentId:String)
data class TokenVo(val token:String,val userId:Int)
sealed class BaseVo{
abstract val token:Token
@ -53,4 +49,12 @@ data class LeaveMessageVo(val message: String, override val token:Token):BaseVo(
data class OnlyToken(override val token: Token):BaseVo()
//data class PageVo(val pageSize:Int=10,val page:, override val token: Token):BaseVo()
data class LeaveMessageFormatVo(val message: String,val studentId: String)
data class LeaveMessageDto(val message: String,val user: UserVo)
data class RegAssociationVo(val name:String, val desc:String,val fileId:Int, override val token: Token):BaseVo()
data class ImageFileDto(val filepath:String,val md5:String,val createTime: Long,val url:String)
data class RegAssociationDto(val name:String,val desc:String,val logo:ImageFileDto)
data class InitManagerDto(val account:String,val originPassword:String)

@ -6,10 +6,12 @@ import cn.smallbun.screw.core.engine.EngineFileType
import cn.smallbun.screw.core.engine.EngineTemplateType
import cn.smallbun.screw.core.execute.DocumentationExecute
import cn.smallbun.screw.core.process.ProcessConfig
import com.google.gson.Gson
import io.ktor.config.*
import io.ktor.http.*
import io.ktor.server.testing.*
import org.jetbrains.exposed.sql.transactions.transaction
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
@ -47,6 +49,8 @@ class ApplicationTest {
put("ktor.deployment.mysql.driverClassName", "com.mysql.cj.jdbc.Driver")
put("ktor.deployment.mysql.username", "root")
put("ktor.deployment.mysql.password", "123456")
put("ktor.deployment.leaveMessage.maxSize", "20")
put("ktor.deployment.filePath", "upload")
}
MySQL(testing = true)
}, test)
@ -60,19 +64,13 @@ class ApplicationTest {
}
}
@Test
fun testUpdateComment(){
initApp {
// updateComment(Users,UserTokens)
transaction {
UserToken.new {
studentId = "6666"
token = "22"
ip = "sdf"
device = "hahha"
}
val s= MainService.getAllLeaveMessage()
Gson().toJson(s)
}
}
}
@ -87,15 +85,12 @@ class ApplicationTest {
}
}
@Test
fun localTime(){
initApp {
transaction {
}
}
@Test
fun checkFileHead(){
val format=File("E:\\JetBrains\\IdeaProjects\\CsamsServer\\build\\classes\\kotlin\\main\\upload\\1621964313158").getFormat()
println(format.format)
}
/**
@ -117,7 +112,7 @@ class ApplicationTest {
//生成模板实现
.produceType(EngineTemplateType.freemarker)
//自定义文件名称
.fileName(fileName).build();
.fileName(fileName).build()
println("数据库文档输出路径${engineConfig.fileOutputDir}")
//忽略表
// val ignoreTableName = ArrayList<String>()

@ -0,0 +1,32 @@
/*
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// This file was automatically generated from channels.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleChannel04
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
fun main() = runBlocking {
val numbers = produceNumbers() // produces integers from 1 and on
val squares = square(numbers) // squares integers
repeat(5) {
delay(1000)
println(squares.receive()) // print first five
}
println("Done!") // we are done
coroutineContext.cancelChildren() // cancel children coroutines
}
@OptIn(ExperimentalCoroutinesApi::class)
fun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
@OptIn(ExperimentalCoroutinesApi::class)
fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
for (x in numbers) send(x * x)
}
Loading…
Cancel
Save