18 changed files with 702 additions and 9 deletions
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
package com.cloud.kicc.system.api.entity; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
import com.cloud.kicc.common.data.entity.CommonEntity; |
||||
import io.swagger.annotations.ApiModel; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
import lombok.EqualsAndHashCode; |
||||
import lombok.experimental.Accessors; |
||||
|
||||
import javax.validation.constraints.NotBlank; |
||||
import java.time.LocalDateTime; |
||||
|
||||
/** |
||||
* <p> |
||||
* IM聊天内容 |
||||
* </p> |
||||
* |
||||
* @author wangxiang4 |
||||
* @since 2023-11-15 |
||||
*/ |
||||
@Data |
||||
@EqualsAndHashCode(callSuper = false) |
||||
@Accessors(chain = true) |
||||
@TableName(value = "sys_im_content", excludeProperty = { "createById", "createByName", "createTime", "updateById", "updateByName", "updateTime", "remarks" }) |
||||
@ApiModel(value = "ImContent对象", description = "IM聊天内容") |
||||
public class ImContent extends CommonEntity { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
@ApiModelProperty("主键") |
||||
private String id; |
||||
|
||||
@ApiModelProperty("发送者") |
||||
@NotBlank(message = "发送者ID不能为空") |
||||
private String sendUserId; |
||||
|
||||
@ApiModelProperty("发送时间") |
||||
private LocalDateTime sendTime; |
||||
|
||||
@ApiModelProperty("接收者") |
||||
@NotBlank(message = "接收者ID不能为空") |
||||
private String receiveUserId; |
||||
|
||||
@ApiModelProperty("接收时间") |
||||
private LocalDateTime receiveTime; |
||||
|
||||
@ApiModelProperty("内容") |
||||
private String content; |
||||
|
||||
@ApiModelProperty("内容类型") |
||||
@NotBlank(message = "发送内容类型不能为空") |
||||
private String contentType; |
||||
|
||||
@ApiModelProperty("状态") |
||||
private String status; |
||||
|
||||
@ApiModelProperty("附件") |
||||
private String files; |
||||
|
||||
@ApiModelProperty("撤销标记") |
||||
private String revert; |
||||
|
||||
} |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
package com.cloud.kicc.system.api.enums; |
||||
|
||||
import lombok.Getter; |
||||
import lombok.RequiredArgsConstructor; |
||||
|
||||
/** |
||||
*<p> |
||||
* IM消息类型 |
||||
*</p> |
||||
* |
||||
* @Author: wangxiang4 |
||||
* @Since: 2023/11/15 |
||||
*/ |
||||
@Getter |
||||
@RequiredArgsConstructor |
||||
public enum ImMessageTypeEnum { |
||||
|
||||
|
||||
TEXT("0", "文本"), |
||||
|
||||
AUDIO("1", "音频"); |
||||
|
||||
|
||||
private final String value; |
||||
|
||||
|
||||
private final String description; |
||||
|
||||
} |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
package com.cloud.kicc.system.config; |
||||
|
||||
import lombok.Data; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
|
||||
/** |
||||
*<p> |
||||
* ai 配置 |
||||
*</p> |
||||
* |
||||
* @Author: wangxiang4 |
||||
* @Since: 2023/11/15 |
||||
*/ |
||||
@Data |
||||
@RefreshScope |
||||
@Configuration |
||||
@ConfigurationProperties("openai.api") |
||||
public class OpenAiConfigProperties { |
||||
|
||||
/** |
||||
* change this to an `accessToken` extracted from the ChatGPT site's |
||||
* `<a href="https://chat.openai.com/api/auth/session">...</a>` response |
||||
*/ |
||||
private String token; |
||||
|
||||
/** OpenAI API Base URL - <a href="https://api.openai.com">...</a> */ |
||||
private String baseUrl; |
||||
|
||||
/** OpenAI API Model - <a href="https://platform.openai.com/docs/models">...</a> */ |
||||
private String model; |
||||
|
||||
/** timeout time unit seconds */ |
||||
private int timeout = 10; |
||||
|
||||
} |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
package com.cloud.kicc.system.controller; |
||||
|
||||
import cn.hutool.core.util.StrUtil; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.cloud.kicc.common.core.api.R; |
||||
import com.cloud.kicc.common.core.constant.AppConstants; |
||||
import com.cloud.kicc.common.core.exception.CheckedException; |
||||
import com.cloud.kicc.common.security.annotation.Inner; |
||||
import com.cloud.kicc.common.security.util.SecurityUtils; |
||||
import com.cloud.kicc.system.api.entity.ImContent; |
||||
import com.cloud.kicc.system.service.IImContentService; |
||||
import lombok.AllArgsConstructor; |
||||
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import javax.validation.Valid; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
*<p> |
||||
* ChatGpt APi Support |
||||
*</p> |
||||
* |
||||
* @Author: wangxiang4 |
||||
* @Since: 2023/11/15 |
||||
*/ |
||||
@RestController |
||||
@AllArgsConstructor |
||||
@RequestMapping(AppConstants.APP_SYSTEM + "/ai") |
||||
public class ChatGptController { |
||||
|
||||
private final IImContentService iImContentService; |
||||
|
||||
@Inner(false) |
||||
@GetMapping("/chat/message") |
||||
public R list(Page page, ImContent imContent) { |
||||
if (StrUtil.isBlank(imContent.getSendUserId()) || StrUtil.isBlank(imContent.getReceiveUserId())) |
||||
throw new CheckedException("当前发送者ID与接收者ID必填!"); |
||||
// 查询一个会话内的聊天记录
|
||||
SecurityUtils.openInterfaceTemporaryLoginSession(imContent.getSendUserId()); |
||||
IPage<Map<String, Object>> result = iImContentService.listHistoryMessage(page, imContent); |
||||
return R.ok(result.getRecords(), result.getTotal()); |
||||
} |
||||
|
||||
|
||||
@Inner(false) |
||||
@PostMapping("/chat/completions") |
||||
public R completions(@Valid @ModelAttribute ImContent imContent, @RequestPart(value = "file", required = false) MultipartFile file) { |
||||
return R.ok(iImContentService.completions(imContent, file)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
package com.cloud.kicc.system.mapper; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.cloud.kicc.system.api.entity.ImContent; |
||||
import org.apache.ibatis.annotations.Param; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <p> |
||||
* IM聊天内容 Mapper 接口 |
||||
* </p> |
||||
* |
||||
* @author wangxiang4 |
||||
* @since 2023-11-15 |
||||
*/ |
||||
public interface ImContentMapper extends BaseMapper<ImContent> { |
||||
|
||||
IPage<Map<String, Object>> listHistoryMessage(Page page, @Param("ew") ImContent imContent); |
||||
|
||||
|
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
package com.cloud.kicc.system.service; |
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.baomidou.mybatisplus.extension.service.IService; |
||||
import com.cloud.kicc.system.api.entity.ImContent; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <p> |
||||
* IM聊天内容 服务类 |
||||
* </p> |
||||
* |
||||
* @author wangxiang4 |
||||
* @since 2023-11-15 |
||||
*/ |
||||
public interface IImContentService extends IService<ImContent> { |
||||
|
||||
IPage<Map<String, Object>> listHistoryMessage(Page page, ImContent imContent); |
||||
|
||||
ImContent completions(ImContent imContent, MultipartFile file); |
||||
|
||||
} |
@ -0,0 +1,195 @@
@@ -0,0 +1,195 @@
|
||||
package com.cloud.kicc.system.service.impl; |
||||
|
||||
import cn.hutool.core.io.FileUtil; |
||||
import cn.hutool.core.util.IdUtil; |
||||
import cn.hutool.core.util.StrUtil; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
import com.cloud.kicc.common.core.exception.CheckedException; |
||||
import com.cloud.kicc.common.security.util.SecurityUtils; |
||||
import com.cloud.kicc.system.api.entity.ImContent; |
||||
import com.cloud.kicc.system.api.enums.ImMessageTypeEnum; |
||||
import com.cloud.kicc.system.mapper.ImContentMapper; |
||||
import com.cloud.kicc.system.service.FileService; |
||||
import com.cloud.kicc.system.service.IImContentService; |
||||
import com.cloud.kicc.system.util.AiUtil; |
||||
import com.pig4cloud.plugin.oss.OssProperties; |
||||
import com.pig4cloud.plugin.oss.service.OssTemplate; |
||||
import com.theokanning.openai.audio.CreateSpeechRequest; |
||||
import com.theokanning.openai.audio.CreateTranscriptionRequest; |
||||
import com.theokanning.openai.audio.TranscriptionResult; |
||||
import com.theokanning.openai.completion.chat.ChatCompletionChoice; |
||||
import com.theokanning.openai.completion.chat.ChatCompletionResult; |
||||
import com.theokanning.openai.completion.chat.ChatMessage; |
||||
import com.theokanning.openai.completion.chat.ChatMessageRole; |
||||
import com.theokanning.openai.service.OpenAiService; |
||||
import lombok.RequiredArgsConstructor; |
||||
import lombok.SneakyThrows; |
||||
import okhttp3.ResponseBody; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import java.io.File; |
||||
import java.time.LocalDateTime; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Objects; |
||||
import java.util.Optional; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* <p> |
||||
* IM聊天内容 服务实现类 |
||||
* </p> |
||||
* |
||||
* @author wangxiang4 |
||||
* @since 2023-11-15 |
||||
*/ |
||||
@Service |
||||
@RequiredArgsConstructor |
||||
public class ImContentServiceImpl extends ServiceImpl<ImContentMapper, ImContent> implements IImContentService { |
||||
|
||||
private final FileService fileService; |
||||
|
||||
private final OssProperties ossProperties; |
||||
|
||||
private final OssTemplate ossTemplate; |
||||
|
||||
@Override |
||||
public IPage<Map<String, Object>> listHistoryMessage(Page page, ImContent imContent) { |
||||
return baseMapper.listHistoryMessage(page, imContent); |
||||
} |
||||
|
||||
@Override |
||||
@Transactional(rollbackFor = Exception.class) |
||||
@SneakyThrows |
||||
public ImContent completions(ImContent imContent, MultipartFile file) { |
||||
SecurityUtils.openInterfaceTemporaryLoginSession(imContent.getSendUserId()); |
||||
if (imContent.getContentType().equals(ImMessageTypeEnum.AUDIO.getValue())) { |
||||
Optional.ofNullable(file).orElseThrow(() -> new CheckedException("当前语音文件为空,请检查后重试!")); |
||||
OpenAiService openAiService = AiUtil.getOpenAiService(); |
||||
String speechName = "speech.mp3"; |
||||
String sendFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()); |
||||
String receiveFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(speechName); |
||||
|
||||
// 构建发送文件信息进行OSS存储
|
||||
com.cloud.kicc.system.api.entity.File sendOssFile = new com.cloud.kicc.system.api.entity.File() |
||||
.setFileName(sendFileName) |
||||
.setBucketName(ossProperties.getBucketName()) |
||||
.setOriginal(file.getOriginalFilename()) |
||||
.setType(FileUtil.extName(file.getOriginalFilename())) |
||||
.setFileSize(file.getSize()) |
||||
.setMimeType(file.getContentType()); |
||||
ossTemplate.putObject(ossProperties.getBucketName(), sendFileName, file.getContentType(), file.getInputStream()); |
||||
String sendVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), sendFileName); |
||||
sendOssFile.setAvailablePath(sendVoiceUrl); |
||||
fileService.save(sendOssFile); |
||||
imContent.setFiles(sendOssFile.getId()); |
||||
|
||||
// 语音转文字
|
||||
File voiceFile = File.createTempFile(sendFileName, null); |
||||
CreateTranscriptionRequest request = CreateTranscriptionRequest.builder() |
||||
.model("whisper-1") |
||||
.language("zh") |
||||
.build(); |
||||
FileUtil.writeBytes(file.getBytes(), voiceFile); |
||||
TranscriptionResult transcriptionResult = openAiService.createTranscription(request, voiceFile); |
||||
if (voiceFile.delete()) { |
||||
System.out.println("已成功删除临时文件!"); |
||||
} |
||||
if (StrUtil.isBlank(transcriptionResult.getText())) { |
||||
throw new CheckedException("Ai语音转文字为空解析失败!"); |
||||
} |
||||
|
||||
imContent.setContent(transcriptionResult.getText()); |
||||
ImContent content = askChatCompletion(imContent); |
||||
content.setContentType(ImMessageTypeEnum.AUDIO.getValue()); |
||||
|
||||
// 文字转语音
|
||||
CreateSpeechRequest createSpeechRequest = CreateSpeechRequest.builder() |
||||
.model("tts-1") |
||||
.input(content.getContent()) |
||||
.voice("nova") |
||||
.responseFormat(FileUtil.extName(speechName)) |
||||
.speed(1.0) |
||||
.build(); |
||||
ResponseBody responseBody = openAiService.createSpeech(createSpeechRequest); |
||||
|
||||
// 构建发送文件信息进行OSS存储
|
||||
com.cloud.kicc.system.api.entity.File receiveOssFile = new com.cloud.kicc.system.api.entity.File() |
||||
.setFileName(receiveFileName) |
||||
.setBucketName(ossProperties.getBucketName()) |
||||
.setOriginal(speechName) |
||||
.setType(FileUtil.extName(speechName)) |
||||
.setFileSize(responseBody.contentLength()) |
||||
.setMimeType(Objects.requireNonNull(responseBody.contentType()).toString()); |
||||
ossTemplate.putObject(ossProperties.getBucketName(), receiveFileName, Objects.requireNonNull(responseBody.contentType()).toString(), responseBody.byteStream()); |
||||
String receiveVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), receiveFileName); |
||||
receiveOssFile.setAvailablePath(receiveVoiceUrl); |
||||
fileService.save(receiveOssFile); |
||||
|
||||
// 保存AI回复聊天记录
|
||||
imContent.setFiles(receiveOssFile.getId()); |
||||
super.save(content); |
||||
return content; |
||||
} else { |
||||
// 保存AI回复聊天记录
|
||||
ImContent content = askChatCompletion(imContent); |
||||
super.save(content); |
||||
return content; |
||||
} |
||||
} |
||||
|
||||
private ImContent askChatCompletion(ImContent imContent) { |
||||
if (StrUtil.isBlank(imContent.getContent())) { |
||||
throw new CheckedException("提问内容不能为空请检查!"); |
||||
} |
||||
// 保存用户发送聊天记录
|
||||
imContent.setSendUserId(SecurityUtils.getCasUser().getId()); |
||||
imContent.setSendTime(LocalDateTime.now()); |
||||
imContent.setReceiveUserId(imContent.getReceiveUserId()); |
||||
imContent.setReceiveTime(LocalDateTime.now()); |
||||
super.save(imContent); |
||||
|
||||
// 查询当前历史消息,进行AI上下文消息合并
|
||||
List<ImContent> imContents = super.list(Wrappers.<ImContent>lambdaQuery().and(i -> |
||||
i.eq(ImContent::getSendUserId, imContent.getSendUserId()) |
||||
.eq(ImContent::getReceiveUserId, imContent.getReceiveUserId()) |
||||
).or(i -> |
||||
i.eq(ImContent::getSendUserId, imContent.getReceiveUserId()) |
||||
.eq(ImContent::getReceiveUserId, imContent.getSendUserId()) |
||||
) .orderByAsc(ImContent::getSendTime)); |
||||
|
||||
// 历史上下文消息
|
||||
List<ChatMessage> historyMessages = imContents.stream().map(item -> { |
||||
ChatMessage chatMessage = new ChatMessage(); |
||||
chatMessage.setRole(StrUtil.equals(item.getSendUserId(), imContent.getSendUserId()) ? ChatMessageRole.USER.value() : ChatMessageRole.ASSISTANT.value()); |
||||
chatMessage.setContent(item.getContent()); |
||||
return chatMessage; |
||||
}).collect(Collectors.toList()); |
||||
|
||||
// 提问消息
|
||||
ChatMessage askMessage = new ChatMessage(ChatMessageRole.USER.value(), imContent.getContent()); |
||||
historyMessages.add(askMessage); |
||||
|
||||
ChatCompletionResult chatCompletionResult = AiUtil.getChatCompletion(historyMessages); |
||||
List<ChatCompletionChoice> choiceList = chatCompletionResult.getChoices(); |
||||
|
||||
if (choiceList.isEmpty()) { |
||||
throw new CheckedException("Ai生成解析失败!"); |
||||
} |
||||
|
||||
// 构建AI生成消息
|
||||
return new ImContent() |
||||
.setSendUserId(imContent.getReceiveUserId()) |
||||
.setSendTime(LocalDateTime.now()) |
||||
.setReceiveUserId(SecurityUtils.getCasUser().getId()) |
||||
.setReceiveTime(LocalDateTime.now()) |
||||
.setContent(choiceList.get(0).getMessage().getContent()) |
||||
.setContentType(ImMessageTypeEnum.TEXT.getValue()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
package com.cloud.kicc.system.util; |
||||
|
||||
import cn.hutool.core.map.MapUtil; |
||||
import com.cloud.kicc.common.core.util.SpringContextHolderUtil; |
||||
import com.cloud.kicc.common.security.util.SecurityUtils; |
||||
import com.cloud.kicc.system.config.OpenAiConfigProperties; |
||||
import com.theokanning.openai.client.OpenAiApi; |
||||
import com.theokanning.openai.completion.chat.*; |
||||
import com.theokanning.openai.service.OpenAiService; |
||||
import lombok.experimental.UtilityClass; |
||||
import okhttp3.OkHttpClient; |
||||
import retrofit2.Retrofit; |
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; |
||||
import retrofit2.converter.jackson.JacksonConverterFactory; |
||||
|
||||
import java.time.Duration; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
*<p> |
||||
* Ai 调用工具 |
||||
*</p> |
||||
* |
||||
* @Author: wangxiang4 |
||||
* @Since: 2023/11/16 |
||||
*/ |
||||
@UtilityClass |
||||
public class AiUtil { |
||||
|
||||
OpenAiConfigProperties openAiConfigProperties = SpringContextHolderUtil.getBean(OpenAiConfigProperties.class); |
||||
|
||||
/** |
||||
* 获取OpenAiService |
||||
*/ |
||||
public OpenAiService getOpenAiService() { |
||||
OkHttpClient client = OpenAiService.defaultClient(openAiConfigProperties.getToken(), Duration.ofSeconds(openAiConfigProperties.getTimeout())); |
||||
Retrofit retrofit = new Retrofit.Builder() |
||||
.baseUrl(openAiConfigProperties.getBaseUrl()) |
||||
.client(client) |
||||
.addConverterFactory(JacksonConverterFactory.create(OpenAiService.defaultObjectMapper())) |
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) |
||||
.build(); |
||||
OpenAiApi api = retrofit.create(OpenAiApi.class); |
||||
return new OpenAiService(api); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* <a href="https://platform.openai.com/docs/api-reference/chat/create">...</a> |
||||
*/ |
||||
public ChatCompletionResult getChatCompletion(List<ChatMessage> historyMessages) { |
||||
String rule = "是与AI助手的对话。助手乐于助人,富有创造力,聪明每次回答限制在300字以内不得超过300字。"; |
||||
List<ChatMessage> messages = new ArrayList<>(); |
||||
ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), rule); |
||||
messages.add(systemMessage); |
||||
messages.addAll(historyMessages); |
||||
ChatCompletionRequest request = ChatCompletionRequest.builder() |
||||
.model(openAiConfigProperties.getModel()) |
||||
.messages(messages) |
||||
.n(1) |
||||
.frequencyPenalty(1.0) |
||||
.presencePenalty(1.0) |
||||
.maxTokens(160) |
||||
.topP(0.8) |
||||
.user(SecurityUtils.getCasUser().getId()) |
||||
.build(); |
||||
return getOpenAiService().createChatCompletion(request); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
<mapper namespace="com.cloud.kicc.system.mapper.ImContentMapper"> |
||||
|
||||
<select id="listHistoryMessage" resultType="Map"> |
||||
select |
||||
im.id, |
||||
im.send_user_id, |
||||
im.send_time, |
||||
im.receive_user_id, |
||||
im.receive_time, |
||||
im.content, |
||||
im.content_type, |
||||
im.status, |
||||
im.files, |
||||
im.revert, |
||||
im.tenant_id, |
||||
sf.file_name, |
||||
sf.bucket_name, |
||||
sf.original, |
||||
sf.type, |
||||
sf.file_size, |
||||
sf.available_path, |
||||
sf.duration, |
||||
sf.mime_type |
||||
from |
||||
sys_im_content im left join sys_file sf on im.files = sf.id |
||||
<where> |
||||
im.del_flag = '0' |
||||
and (im.send_user_id = #{ew.sendUserId} and im.receive_user_id = #{ew.receiveUserId}) |
||||
or (im.send_user_id = #{ew.receiveUserId} and im.receive_user_id = #{ew.sendUserId}) |
||||
</where> |
||||
order by im.send_time asc |
||||
</select> |
||||
|
||||
</mapper> |
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
import com.baomidou.mybatisplus.generator.AutoGenerator; |
||||
import com.baomidou.mybatisplus.generator.config.*; |
||||
import com.cloud.kicc.common.data.entity.CommonEntity; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
*<p> |
||||
* mysql crud代码自动生成 |
||||
*</p> |
||||
* |
||||
* @Author: wangxiang4 |
||||
* @Date: 2022/7/22 |
||||
*/ |
||||
public class SimpleCrudGeneratorTest { |
||||
|
||||
/** 代码生成全局配置 */ |
||||
interface Config { |
||||
|
||||
String url = "jdbc:mysql://139.9.72.189:8052/db_kicc?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true"; |
||||
|
||||
String username = "u_kanglai_account"; |
||||
|
||||
String password = "$kanglai.<2021>#"; |
||||
|
||||
String author = "wangxiang4"; |
||||
|
||||
String rootOutputDir = "/Users/wangxiang/IdeaProjects/org/kicc/kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java"; |
||||
|
||||
String entityOutputDir = "/Users/wangxiang/IdeaProjects/org/kicc/kicc-platform/kicc-platform-api/kicc-system-api/src/main/java/com/cloud/kicc/system/api/entity"; |
||||
|
||||
String mapperXmlOutputDir = "/Users/wangxiang/IdeaProjects/org/kicc/kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/resources/mapper"; |
||||
|
||||
String packageParent = "com.cloud.kicc.system"; |
||||
|
||||
String packageService = "service"; |
||||
|
||||
String packageEntity = "api.entity"; |
||||
|
||||
String packageServiceImpl = "service.impl"; |
||||
|
||||
String packageMapper = "mapper"; |
||||
|
||||
String packageController = "controller"; |
||||
|
||||
String[] includeTable = { "sys_im_content" }; |
||||
|
||||
String[] filterEntityTablePrefix = { "sys_" }; |
||||
|
||||
String[] superEntityColumns = { "createById", "createByName", "createTime", "updateById","updateByName", "updateTime", "remarks", "delFlag" }; |
||||
|
||||
String[] ignoreColumns = { "tenant_id" }; |
||||
|
||||
} |
||||
|
||||
@Test |
||||
/** 运行代码生成 */ |
||||
public void CrudSimpleGenerator() { |
||||
|
||||
AutoGenerator generator = new AutoGenerator(new DataSourceConfig.Builder(Config.url, Config.username, Config.password).build()); |
||||
// 全局配置 参考:https://github.com/baomidou/generator#%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AEglobalconfig
|
||||
generator.global(new GlobalConfig.Builder() |
||||
.author(Config.author) |
||||
.enableSwagger() |
||||
.fileOverride() |
||||
.outputDir(Config.rootOutputDir) |
||||
.build() |
||||
); |
||||
// 包路径配置 参考:https://github.com/baomidou/generator#%E5%8C%85%E9%85%8D%E7%BD%AEpackageconfig
|
||||
Map<OutputFile, String> pathInfos = new ConcurrentHashMap(); |
||||
pathInfos.put(OutputFile.entity, Config.entityOutputDir); |
||||
pathInfos.put(OutputFile.mapperXml, Config.mapperXmlOutputDir); |
||||
generator.packageInfo(new PackageConfig.Builder() |
||||
.parent(Config.packageParent) |
||||
.service(Config.packageService) |
||||
.entity(Config.packageEntity) |
||||
.serviceImpl(Config.packageServiceImpl) |
||||
.mapper(Config.packageMapper) |
||||
.controller(Config.packageController) |
||||
.pathInfo(pathInfos) |
||||
.build() |
||||
); |
||||
// 策略配置 参考:https://github.com/baomidou/generator#%E7%AD%96%E7%95%A5%E9%85%8D%E7%BD%AEstrategyconfig
|
||||
generator.strategy(new StrategyConfig.Builder() |
||||
.addInclude(Config.includeTable) |
||||
.addTablePrefix(Config.filterEntityTablePrefix) |
||||
.entityBuilder() |
||||
.enableChainModel() |
||||
.enableLombok() |
||||
.enableRemoveIsPrefix() |
||||
.superClass(CommonEntity.class) |
||||
.addSuperEntityColumns(Config.superEntityColumns) |
||||
.addIgnoreColumns(Config.ignoreColumns) |
||||
.build() |
||||
); |
||||
generator.execute(); |
||||
} |
||||
|
||||
|
||||
} |
Loading…
Reference in new issue