基于javaweb+mysql的springboot小说阅读系统(java+springboot+vue+maven+mysql+redis)
运行环境
Java≥8、MySQL≥5.7、Node.js≥10
开发工具
后端:eclipse/idea/myeclipse/sts等均可配置运行
前端:WebStorm/VSCode/HBuilderX等均可
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb+mysql的SpringBoot小说阅读系统(java+springboot+vue+maven+mysql+redis)
环境配置:
Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。
项目技术:
Spring + SpringBoot+ mybatis + Maven + Vue 等等组成,B/S模式 + Maven管理等等。
return ResponseResult.success();
}
}
/**
* <p>
* 收藏表 前端控制器
* </p>
*
*/
@RestController
@RequestMapping("/userCollection")
public class UserCollectionController {
@Autowired
UserCollectionService userCollectionService;
@Autowired
SysUserCacheService sysUserCacheService;
@GetMapping("/list")
@SysLogs("获取收藏列表")
public ResponseResult list(HttpServletRequest request, CollectionDto collectionDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
public ReadHistory getHistoryByUserId(String userId, String novelId, String novelChaperId) {
QueryWrapper<ReadHistory> qw = new QueryWrapper<>();
qw.eq(SqlConstant.NOVEL_ID,novelId);
qw.eq(SqlConstant.LAST_CHAPTER_ID,novelChaperId);
qw.eq(SqlConstant.USER_ID,userId);
qw.eq(SqlConstant.TYPE,TypeEnums.HISTORY_RECORD.getCode());
return this.getOne(qw);
}
@Override
public void saveBookMark(SysUser sysUser, ReadHistoryDto readHistoryDto) {
//判断是修改还是增加
if(StringUtils.isEmpty(readHistoryDto.getId())){
//直接增加,不需要判断重复
this.addHistory(readHistoryDto, sysUser);
}else{
//直接修改,只能修改名字
ReadHistory readHistory=new ReadHistory();
readHistory.setId(readHistoryDto.getId());
readHistory.setBookMarkName(readHistoryDto.getMarkName());
this.updateById(readHistory);
}
}
/**
* 更新用户阅读历史
* @param readHistoryDto
* @param history
* @param sysUser
*/
private void updateHistory(ReadHistoryDto readHistoryDto, ReadHistory history, SysUser sysUser) {
//他有可能之前没有登录,现在登录了
if(StringUtils.isNotEmpty(sysUser.getId())){
history.setUserId(sysUser.getId());
}
history.setUpdateTime(new Date());
history.setLastChapterId(readHistoryDto.getNovelChaperId());
history.setReadPosition(readHistoryDto.getPosition());
history.setReadAllPosition(readHistoryDto.getAllPosition());
history.setBookMarkName(readHistoryDto.getMarkName());
//如果是根据userId找的,他有可能换了ip
history.setIp(readHistoryDto.getIp());
this.updateById(history);
}
/**
* 保存历史记录
* @param readHistoryDto
}
/**
* <p>
* 章节表 前端控制器
* </p>
*
*/
@RestController
@RequestMapping("/novelChapter")
public class NovelChapterController {
@Autowired
private NovelChapterService novelChapterService;
@GetMapping("/list")
@SysLogs("获取小说章节列表")
public ResponseResult getNovelChapter(HttpServletRequest request,@RequestParam("id")String id){
if(StringUtils.isEmpty(id)){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
SysUser sysUser = RequestUtils.getSysUser(request);
return ResponseResult.success(novelChapterService.getNovelChapter(sysUser,id));
}
@GetMapping("/content")
@SysLogs("获取小说内容")
public ResponseResult getNovelContext(HttpServletRequest request,NovelChapterDto novelChapterDto){
}
return false;
}
/**
* 用户未登录
* @param response
* @throws IOException
*/
private void notLogin(HttpServletResponse response) throws IOException {
log.info("用户未登录");
response.setContentType(StrConstant.CONTENT_TYPE);
response.setCharacterEncoding(StrConstant.DEFAULT_CHARTSET);
response.setStatus(ResponeseCode.SUCCESS.code);
OutputStream outputStream = response.getOutputStream();
String resultStr = JsonUtils.ObjectToJsonStr(ResponseResult.error(CodeMsgEnums.USER_NOT_LOGIN));
outputStream.write(resultStr.getBytes(StrConstant.DEFAULT_CHARTSET));
outputStream.flush();
outputStream.close();
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
*/
void downloadNovel(HttpServletRequest request, HttpServletResponse response, DownloadDto downloadDto, SysUser sysUser);
/**
* 校验小说是否可以访问
* @param novel
* @param sysUser
* @return
*/
void checkNovelStatus(Novel novel, SysUser sysUser);
/**
* 发布小说
* @param sysUser
* @param novelDto
*/
void publicNovel(SysUser sysUser, NovelDto novelDto);
/**
* 审核小说
* @param sysUser
* @param novelDto
*/
void auditNovel(SysUser sysUser, NovelDto novelDto);
/**
* 取消发布
* @param sysUser
* @param novelDto
*/
void cancelPublic(SysUser sysUser, NovelDto novelDto);
/**
* 收藏数+1
* @param id
*/
void addCollectionNum(String id);
}
}
//3、判断是否需要收藏
if(novelUploadDto.getIsCollect()!=null&&novelUploadDto.getIsCollect()){
userCollectionService.saveCollection(sysUser,novel,TypeEnums.USER_CHANNEL.getCode());
novel.setNovelCollection(NumConstant.ONE);
}
//3、设置业务参数
if(TypeEnums.ADMIN_ROLE.getCode().equals(sysUser.getRoleType())){
//管理员上传直接设为公开
novel.setNovelUploadType(TypeEnums.PUBLIC_NOVEL.getCode());
novel.setNovelStatus(TypeEnums.SUCCESS_AUDIT.getCode());
}else{
//用户上传则先设为私有,再看需不需要发布审核
novel.setNovelUploadType(TypeEnums.PRIVATE_NOVEL.getCode());
if(novelUploadDto.getIsPublic()!=null&&novelUploadDto.getIsPublic()){
novel.setNovelStatus(TypeEnums.WAIT_AUDIT.getCode());
}else{
novel.setNovelStatus(TypeEnums.NOT_AUDIT.getCode());
}
}
this.save(novel);
uploadNovels.add(novel);
}
//结束后加入动态
dynamicService.addUploadDynamic(sysUser,uploadNovels);
}
@Override
public Novel saveTxtNovel(SysUser sysUser, NovelUploadDto novelUploadDto, ReadFile file, MultipartFile novelFile) {
//1、设置基本属性
Novel novel = this.setNovelParam(sysUser,file,novelUploadDto);
//3、解析文件生成小说章节数
FileInfoPojo fileInfoPojo = novelChapterService.analysisTxtFile(sysUser, novelFile, file, novel);
novel.setNovelTotal(fileInfoPojo.getTotal());
novel.setNovelWordNum(fileInfoPojo.getWordNum());
if(StringUtils.isEmpty(novel.getNovelTitle())){
novel.setNovelTitle(StringUtils.getFileName(file.getFileName()));
}
return novel;
}
@Override
public Novel saveEpubNovel(SysUser sysUser, NovelUploadDto novelUploadDto, ReadFile file, MultipartFile novelFile) {
//1、设置基本
Novel novel = this.setNovelParam(sysUser,file,novelUploadDto);
//3、解析文件生成小说章节数
EpubInfoPojo epubInfoPojo = novelChapterService.analysisEpubFile(sysUser, novelFile, file, novel);
Novel saveNovel = epubInfoPojo.getNovel();
if(StringUtils.isEmpty(saveNovel.getNovelTitle())){
saveNovel.setNovelTitle(StringUtils.getFileName(file.getFileName()));
}
//2、解析epub文件。并存放到章节表中
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
/**
* 可不登录调用的接口
*
*/
if(log.isDebugEnabled()){
log.info("logPointCut");
}
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable{
Object proceed = point.proceed();
saveSysLog(point);
return proceed;
}
protected void saveSysLog(ProceedingJoinPoint point) {
MethodSignature signature=(MethodSignature) point.getSignature();
Method method=signature.getMethod();
SysLog sysLog=new SysLog();
SysLogs sysLogs=method.getAnnotation(SysLogs.class);
HttpServletRequest request= HttpClientUtils.getHttpServletRequest();
SysUser sysUser = RequestUtils.getSysUser(request);
String ip = HttpClientUtils.getIp(request);
//名字
String className=point.getTarget().getClass().getName();
String methodName=point.getSignature().getName();
//参数
Object[] args = point.getArgs();
String s = Arrays.toString(args);
String param=s.length()<500?s:"参数过大,不予记录";
log.info("请求接口:{}",className);
log.info("方法名:{}",methodName+"("+param+")");
log.info("请求方式:{}",request.getMethod());
log.info("请求ip:{}",ip);
log.info("请求人:{}",sysUser.getUserName());
sysLog.setId(StringUtils.getUuid());
sysLog.setCreateTime(new Date());
sysLog.setIp(ip);
sysLog.setMethod(request.getMethod());
sysLog.setParam(param);
sysLog.setPath(className+"."+methodName+"()");
sysLog.setOperatorUserName(sysUser.getUserName());
sysLog.setOperatorAccountName(sysUser.getAccountName());
sysLog.setLogDescribe(sysLogs.value());
sysLogService.save(sysLog);
}
/**
* <p>
* 前端控制器
* </p>
*
*/
@RestController
@RequestMapping("/sysNotice")
public class SysNoticeController {
@Autowired
private SysNoticeService sysNoticeService;
@PostMapping("/notice")
@SysLogs("新增或修改公告")
public ResponseResult addOrEditNotice(HttpServletRequest request, @RequestBody SysNotice sysNotice){
SysUser sysUser = ShiroUtils.getSysUser(request);
if(StringUtils.isEmpty(sysNotice.getId())){
//为空是新增
sysNoticeService.addNotice(sysUser,sysNotice);
}else {
//不为空是修改
sysNoticeService.editNotice(sysUser,sysNotice);
}
return ResponseResult.success();
}
@GetMapping("/list")
@SysLogs("公告列表")
public ResponseResult getList(HttpServletRequest request,SysNoticeDto sysNoticeDto){
SysUser sysUser = RequestUtils.getSysUser(request);
return ResponseResult.success(this.sysNoticeService.getList(sysNoticeDto));
}
*
*/
@RestController
@RequestMapping("/dynamic")
public class DynamicController {
@Autowired
private DynamicService dynamicService;
@GetMapping("/list")
@SysLogs("获取动态列表")
public ResponseResult getList(HttpServletRequest request, DynamicDto dynamicDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
return ResponseResult.success(this.dynamicService.getList(sysUser,dynamicDto));
}
@GetMapping("/info")
@SysLogs("获得动态详情")
public ResponseResult getDynamic(HttpServletRequest request,DynamicDto dynamicDto){
if(StringUtils.isEmpty(dynamicDto.getId())){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
return ResponseResult.success(this.dynamicService.getById(dynamicDto.getId()));
}
@PostMapping("/alread")
@SysLogs("标记已读")
public ResponseResult alread(HttpServletRequest request,@RequestBody DynamicDto dynamicDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
this.dynamicService.alread(sysUser,dynamicDto);
return ResponseResult.success();
}
@DeleteMapping("/delete")
@SysLogs("删除动态")
public ResponseResult deleteDynamic(HttpServletRequest request,DynamicDto dynamicDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
this.dynamicService.deleteDynamic(sysUser,dynamicDto);
return ResponseResult.success();
}
* @param sysUser
* @param novelUploadDto
* @param file
* @param novelFile
* @return
*/
Novel saveEpubNovel(SysUser sysUser, NovelUploadDto novelUploadDto, ReadFile file, MultipartFile novelFile);
/**
* 获得小说列表
* @param sysUser
* @param novelDto
* @return
*/
Page<Novel> getNovelList(SysUser sysUser, NovelDto novelDto);
/**
* 获得小说信息
*
* @param sysUser
* @param id
* @param isClick 是否是点击进来的
* @return
*/
Novel getNovelInfo(SysUser sysUser, String id, Boolean isClick);
/**
* 根据id删除小说
* @param ids
*/
void deleteNovel(List<String> ids);
/**
* 根据类型获得排名前几的小说
* @param types
* @return
*/
Map<String,List> getHotNovelDataByType(List<String> types);
/**
* 更新热度
* @param id
*/
void updateNovelHot(String id);
/**
* 更新小说
* @param sysUser
* @param novelUploadDto
*/
void updateNovel(SysUser sysUser, NovelUploadDto novelUploadDto);
/**
* 拦截器
*/
@Slf4j
@Controller
@Component
public class Loginlnterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{
//跨域问题
boolean isOpt = this.handleCors(response,request.getMethod());
if(isOpt){
return true;
/**
* <p>
* 前端控制器
* </p>
*
*/
@RestController
@RequestMapping("/share")
public class ShareController {
@Autowired
private ShareService shareService;
@PostMapping("/addOrEdit")
@SysLogs("创建分享")
public ResponseResult addOrEditShare(HttpServletRequest request,@RequestBody ShareDto shareDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
if(StringUtils.isEmpty(shareDto.getId())){
//新建
return ResponseResult.success(shareService.addShare(sysUser,shareDto));
}else{
//修改
shareService.editShare(sysUser,shareDto);
}
return ResponseResult.success();
}
@GetMapping("/list")
@SysLogs("分享列表")
public ResponseResult shareList(HttpServletRequest request,ShareDto shareDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
return ResponseResult.success(this.shareService.getShareList(sysUser,shareDto));
}
@PostMapping("/checkNeedPwd")
//修改
shareService.editShare(sysUser,shareDto);
}
return ResponseResult.success();
}
@GetMapping("/list")
@SysLogs("分享列表")
public ResponseResult shareList(HttpServletRequest request,ShareDto shareDto){
SysUser sysUser = ShiroUtils.getSysUser(request);
return ResponseResult.success(this.shareService.getShareList(sysUser,shareDto));
}
@PostMapping("/checkNeedPwd")
@SysLogs("校验是否需要需要密码")
public ResponseResult checkNeedPwd(HttpServletRequest request,@RequestBody ShareDto shareDto){
if(StringUtils.isEmpty(shareDto.getId())){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
return ResponseResult.success(this.shareService.checkNeedPwd(shareDto));
}
@PostMapping("/checkPwd")
@SysLogs("校验密码和当前登录人是否正确")
public ResponseResult checkPwd(HttpServletRequest request,@RequestBody ShareDto shareDto){
if(StringUtils.isEmpty(shareDto.getId())){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
SysUser sysUser = RequestUtils.getSysUser(request);
return ResponseResult.success(this.shareService.checkPwd(sysUser,shareDto));
}
@GetMapping("/fileList")
@SysLogs("分享后的文件列表")
public ResponseResult shareFileList(HttpServletRequest request,ShareDto shareDto){
if(StringUtils.isEmpty(shareDto.getId())){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
SysUser sysUser = ShiroUtils.getSysUser(request);
return ResponseResult.success(this.shareService.shareFileList(sysUser,shareDto));
}
}
List<String> list=novelDto.getNovelTypes();
if(CollectionUtils.isEmpty(list)){
list=Lists.newArrayList();
}
list.add(novelDto.getNovelType());
novelDto.setNovelTypes(list);
}
Page<Novel> page = new Page<>(novelDto.getPageNum(),novelDto.getPageSize());
List<Novel> novelList=this.novelMapper.selectNovelList(novelDto,page);
//查询数据字典的所有小说类型
List<SysDict> sysDicts = sysDictMapper.selectList(new QueryWrapper<SysDict>()
.eq(SqlConstant.DICT_CLASS, DictEnums.NOVEL_TYPE.getKey()));
Map<String, SysDict> sysDictMap = sysDicts.stream().collect(Collectors.toMap(SysDict::getDictKey, x -> x));
for (Novel record : novelList) {
//1、查询是否已经收藏
if(!isAdmin){
Integer integer = userCollectionMapper.selectCount(new QueryWrapper<UserCollection>()
.eq(SqlConstant.NOVEL_ID, record.getId()).eq(SqlConstant.USER_ID, sysUser.getId()));
if(integer>0){
record.setIsCollection(TypeEnums.IS_COLLECTION.getCode());
}else{
record.setIsCollection(TypeEnums.NOT_COLLECTION.getCode());
}
}
//2、查询小说类型
if(StringUtils.isNotEmpty(record.getNovelType())){
List<String> list = StringUtils.commaStrToList(record.getNovelType());
List<SysDict> typeList=Lists.newArrayList();
for (String key : list) {
SysDict sysDict = sysDictMap.get(key);
typeList.add(sysDict);
}
List<String> values = list.stream().map(x -> sysDictMap.get(x).getDictValue()).collect(Collectors.toList());
record.setNovelType(StringUtils.listToCommaStr(values));
record.setNovelTypeDict(sysDicts);
record.setNovelTypes(typeList);
}
}
return page.setRecords(novelList);
}
@Override
/**
* <p>
* 章节表 前端控制器
* </p>
*
*/
@RestController
@RequestMapping("/novelChapter")
public class NovelChapterController {
@Autowired
private NovelChapterService novelChapterService;
@GetMapping("/list")
@SysLogs("获取小说章节列表")
public ResponseResult getNovelChapter(HttpServletRequest request,@RequestParam("id")String id){
if(StringUtils.isEmpty(id)){
throw RequestException.fail(CodeMsgEnums.ID_IS_EMPTY.getMsg());
}
SysUser sysUser = RequestUtils.getSysUser(request);
return ResponseResult.success(novelChapterService.getNovelChapter(sysUser,id));
}
@GetMapping("/content")
@SysLogs("获取小说内容")
public ResponseResult getNovelContext(HttpServletRequest request,NovelChapterDto novelChapterDto){
SysUser sysUser = RequestUtils.getSysUser(request);
return ResponseResult.success(novelChapterService.getNovelChapterContext(sysUser,novelChapterDto));
}
}
@Slf4j
public class HttpClientUtils {
private static String unknowStr= "unknown";
/**
* 拦截器
*/
@Slf4j
@Controller
@Component
public class Loginlnterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{
//跨域问题
boolean isOpt = this.handleCors(response,request.getMethod());
if(isOpt){
return true;
}
String token = request.getHeader(StrConstant.AUTHORIZATION);
if(StringUtils.isEmpty(token)){
this.notLogin(response);
return false;
}
JwtToken jwtInfo = JwtUtils.getJwtInfo(token);
if(StringUtils.isNotEmpty(jwtInfo.getAccountName())){
log.info("拦截器认证已登录");
return true;