基于javaweb+mysql的springboot个人博客系统(前后端分离+java+vue+springboot+ssm+mysql+maven+redis)
私信源码获取及调试交流
运行环境
Java≥8、MySQL≥5.7、Node.js≥10
开发工具
后端:eclipse/idea/myeclipse/sts等均可配置运行
前端:WebStorm/VSCode/HBuilderX等均可
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb的SpringBoot个人博客系统(前后端分离+java+vue+springboot+ssm+mysql+maven+redis)
一、项目简述
本系统功能包括:文章展示、热门文章、文章分类、标签云用户登录评论、匿名评论用户留言、匿名留言评论管理、文章发布、文章管理文章数据统计等等.
二、项目运行
环境配置: Jdkl . 8 + + Mysql + HBuilderX ( Webstorm 也行) + Eclispe ( IntelliJ 10 以,三 clispe , MyEclispe , Sts 都支持)。
项目技术: Springboot + Maven + Mybatis + Vue + Redis 组成, BIS 模式+ M aven 等等,附带支付宝沙箱环境以及支付环节代码。
Set<String> tags = articleService.findAllTags();
return tags;
}
@ApiOperation("获取文章的所有月份")
@GetMapping("/archives")
public Set<String> getArchivesMonths() {
Set<String> months = articleService.archivesMonths();
return months;
}
}
/**
* @description 管理博客文章
*/
@RestController("adminArticleController")
@RequestMapping("admin/articles")
@Slf4j
public class ArticleController {
@Autowired
private ArticleService articleService;
@ApiOperation("插入文章")
@PostMapping("/")
public ResultVO insArticle(@RequestBody @Validated ArticleDTO articleDTO) {
articleService.insArticle(articleDTO);
return ResultVO.ok("插入文章成功!");
}
@ApiOperation("修改文章")
@PutMapping("/")
public ResultVO updArticle(@RequestBody @Validated ArticleDTO articleDTO) {
articleService.updArticle(articleDTO);
return ResultVO.ok("更新文章成功!");
}
@ApiOperation("根据对应文章id删除文章")
@DeleteMapping("/{id}")
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResponseEntity<ResultVO> exception(Exception exception) {
exception.printStackTrace();
log.error("message:{}", exception.getMessage());
//未知异常
ResultVO resultVO = ResultVO.error(exception.getMessage());
return new ResponseEntity<>(resultVO, HttpStatus.INTERNAL_SERVER_ERROR);
}
/**
* 结合BeanValid,格式化异常信息
*
* @param ex
* @return
*/
private String getMessage(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
StringBuilder sb = new StringBuilder();
for (FieldError error : bindingResult.getFieldErrors()) {
String field = error.getField();
Object value = error.getRejectedValue();
String msg = error.getDefaultMessage();
String message = String.format("错误字段:%s,错误值:%s,原因:%s;", field, value, msg);
sb.append(message);
}
return sb.toString();
}
}
* @description 拦截器:用于日志打印
*/
@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
@Override
public synchronized boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("request-method:{}", request.getMethod());
log.info("request-url:{}", request.getRequestURL());
String remoteAddr = request.getRemoteAddr();
log.info("remote-addr:{}", remoteAddr);
StringBuffer sb = new StringBuffer();
request.getParameterMap().forEach((k, v) -> sb.append(k).append(Arrays.toString(v)));
log.info("request-parameters:{}", sb.toString());
// 根据ip定位
//((Runnable) () -> {
// try {
// String res = HttpUtil.get(TAOBAO_IP_INFO + "?ip=" + remoteAddr);
// JSONObject jsonObject = JSONUtil.parseObj(res);
// if ("0".equals(jsonObject.get("code"))) {
// JSONObject data = jsonObject.getJSONObject("data");
// log.info("ip-info:country:{}、area:{}、region:{}、city:{}、isp:{}", data.get("country"), data.get("area"), data.get("region"), data.get("city"), data.get("isp"));
// }
// } catch (Exception e) {
// log.error("ip:{}定位出错", remoteAddr);
// }
//}).run();
return true;
}
}
/**
/**
* @description 留言信息api
*/
@RestController
@RequestMapping("comm/message")
public class MessageController {
@Autowired
private MessageService messageService;
@ApiOperation("获取所有留言")
@GetMapping("/")
public List<MessageVO> getMessages() {
List<MessageVO> messages = messageService.findAllMessages();
return messages;
}
@ApiOperation("提交留言")
@PostMapping("/")
public ResultVO leaveAMessage(@RequestBody @Validated MessageDTO messageDTO) {
messageService.insMessage(messageDTO);
return ResultVO.ok("留言成功!");
}
}
/**
* @description 全局异常处理
*/
@ControllerAdvice
@Slf4j
class ApiExceptionHandler {
@ResponseBody
@ExceptionHandler(value = BaseException.class)
public ResponseEntity<ResultVO> handleApiException(Exception exception, HttpServletResponse response) {
BaseException baseException = (BaseException) exception;
if (baseException instanceof TokenExpiredException) {
log.warn("message:{}", exception.getMessage());
response.setStatus(403);
} else {
log.error("message:{}", exception.getMessage());
response.setStatus(500);
}
ResultVO resultVO = ResultVO.error(baseException);
return new ResponseEntity<>(resultVO, HttpStatus.valueOf(response.getStatus()));
}
@ExceptionHandler(value = NoHandlerFoundException.class)
@ResponseBody
public ResponseEntity<ResultVO> handleNoHandlerFoundException(Exception exception) {
log.error("message:{}", exception.getMessage());
ResultVO resultVO = ResultVO.error(exception.getMessage(), RespCode.RESOURCES_NOT_FOUND);
/**
* @description 与文章相关的api
*/
@RestController("commArticleController")
@RequestMapping("comm/articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
@Autowired
private ArticleMapper articleMapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@ApiOperation("根据条件分页显示文章")
@GetMapping("/page")
public PageInfoVO<SimpleArticleVO> getPageArticles(
@ApiParam("页码") @RequestParam(value = "pageNumber", defaultValue = "1", required = false) Integer pageNumber,
@ApiParam("约束条件") @RequestParam(required = false) String condition,
@ApiParam("约束条件对应的信息") @RequestParam(required = false) String data
) {
return articleService.findByCondition(pageNumber, DEFAULT_PAGE_SIZE, condition, data);
}
@ApiOperation("根据文章id获取文章信息")
@GetMapping("/{id}")
public ArticleVO getArticleById(@PathVariable String id) {
return articleService.findArticleById(id);
}
@ApiOperation("获取热门文章列表")
@GetMapping(value = "/hot", produces = "application/json;charset=UTF-8")
public String getHotArticles() {
return redisTemplate.opsForValue().get("hotArticles");
}
@ApiOperation("获取所有文章分类")
@GetMapping("/categories")
public List<Map<String, Object>> getCategories() {
return articleMapper.findCategoriesCount();
}
public ResultVO profile(@RequestBody @Validated ProfileDTO profile) {
configMapper.insert(new ConfigDO(Constants.ConfigKey.NAME, profile.getName()));
configMapper.insert(new ConfigDO(Constants.ConfigKey.PEN_NAME, profile.getPenName()));
configMapper.insert(new ConfigDO(Constants.ConfigKey.MOTTO, profile.getMotto()));
configMapper.insert(new ConfigDO(Constants.ConfigKey.INTRODUCTION, profile.getIntroduction()));
configMapper.insert(new ConfigDO(Constants.ConfigKey.AVATAR, profile.getAvatar()));
configMapper.insert(new ConfigDO(Constants.ConfigKey.WEBSITES, StrUtil.EMPTY));
configService.initConfig();
return ResultVO.ok("个人信息初始化完成");
}
}
/**
* @e-mail 1413979079@qq.com
* @description 自定义图床
*/
@Slf4j
@RestController
@RequestMapping("/admin/image")
public class ImageController {
@Value("${blog.images.path}")
private String imagesPath;
@Value("${blog.url}")
private BlogService blogService;
@Autowired
private Configs configs;
@ApiOperation("获取博客信息")
@GetMapping("/info")
public BlogInfoVO getInfo() {
BlogInfoVO blogInfo = blogService.getBlogInfo();
return blogInfo;
}
@ApiOperation("获取博客配置信息")
@GetMapping("/profile")
public ProfileVO profile() {
return ProfileVO.create(configs);
}
}
/**
* @description 留言信息api
*/
@RestController
@RequestMapping("comm/message")
public class MessageController {
@Autowired
private MessageService messageService;
@ApiOperation("获取所有留言")
@GetMapping("/")
public List<MessageVO> getMessages() {
List<MessageVO> messages = messageService.findAllMessages();
return messages;
}
@ApiOperation("上传图片")
@PostMapping("/upload")
public String upload(@RequestParam("image") MultipartFile multipartFile) {
// "." 、"\"、"|"需要转义
String[] split = multipartFile.getOriginalFilename().split("\\.");
String fileName = UUID.randomUUID().toString() + "." + split[split.length - 1];
try {
File dir = new File(imagesPath);
if (!dir.exists()) {
dir.mkdirs();
}
FileUtil.writeFromStream(multipartFile.getInputStream(), imagesPath + fileName);
String url = uri + "admin/image/get/" + fileName;
log.debug("image-url:{}", url);
return url;
} catch (Exception e) {
log.error(e.getMessage());
throw new ImageUploadFailureException(e);
}
}
@ApiOperation("根据图片地址获取图片")
@GetMapping("/get/{fileName}.{type}")
public void get(HttpServletResponse res, @PathVariable String fileName, @PathVariable String type) {
BufferedInputStream in = null;
ServletOutputStream out = null;
try {
in = FileUtil.getInputStream(imagesPath + fileName + "." + type);
out = res.getOutputStream();
StreamUtils.copy(in, out);
out.flush();
} catch (IOException e) {
log.error(e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.error(e.getMessage());
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
/**
* @e-mail 1413979079@qq.com
* @description 草稿
*/
@RestController
@RequestMapping("admin/draft")
public class DraftController {
@Autowired
private DraftMapper draftMapper;
@ApiOperation("获取所有草稿")
@GetMapping("/")
public List<DraftVO> getAllDrafts() {
List<DraftVO> draftVOS = draftMapper.findAll()
.stream()
.map(DraftVO::create)
.collect(Collectors.toList());
return draftVOS;
}
@ApiOperation("根据id获取对应草稿信息")
@GetMapping("/{id}")
public DraftDO getById(@PathVariable String id) {
DraftDO draftDO = draftMapper.findById(id);
return draftDO;
}
@ApiOperation("新增草稿")
@PostMapping("/")
public Map<String, Object> saveDraft(@RequestBody DraftDTO draftDTO) {
// 生成唯一id
String id = IdUtil.simpleUUID();
DraftDO draftDO = new DraftDO();
draftDO.setTitle(draftDTO.getTitle());
draftDO.setContent(draftDTO.getContent());
draftDO.setGmtUpdate(System.currentTimeMillis());
draftDO.setGmtCreate(draftDO.getGmtUpdate());
*/
@RestController
@RequestMapping("comm/message")
public class MessageController {
@Autowired
private MessageService messageService;
@ApiOperation("获取所有留言")
@GetMapping("/")
public List<MessageVO> getMessages() {
List<MessageVO> messages = messageService.findAllMessages();
return messages;
}
@ApiOperation("提交留言")
@PostMapping("/")
public ResultVO leaveAMessage(@RequestBody @Validated MessageDTO messageDTO) {
messageService.insMessage(messageDTO);
return ResultVO.ok("留言成功!");
}
}
/**
* @e-mail 1413979079@qq.com
* @description 管理员用户
*/
@RestController("adminUserController")
@RequestMapping("/admin/user")
public class UserController {
@Autowired
private ConfigService configService;
@RequestMapping("/token")
public ResultVO token(String token) {
boolean res = configService.checkToken(token);
return res ? ResultVO.ok("已登录") : ResultVO.ok("token已经过期");
}
@PostMapping("/")
public ResultVO login(@RequestBody AdminUserDTO user) {
String token = configService.login(user);
return token != null ? ResultVO.ok(token) : ResultVO.error("登录失败");
@RequestMapping("admin/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@ApiOperation("分页展示评论列表")
@GetMapping("/")
public PageInfoVO<CommentItemVO> getComment(
@RequestParam(value = "pageNumber", defaultValue = "1", required = false) Integer pageNumber) {
PageInfoVO<CommentItemVO> pageInfoVO = commentService.findAllComments(pageNumber);
return pageInfoVO;
}
@ApiOperation("根据id删除对应评论")
@DeleteMapping("/{id}")
public ResultVO delById(@PathVariable Long id) {
commentService.deleteById(id);
return ResultVO.ok("操作成功!");
}
}
/**
* @description 获取blog的信息
*/
@Slf4j
@RestController("commBlogController")
@RequestMapping("/comm/blog")
public class BlogController {
@Autowired
@RestController("commCommentController")
@RequestMapping("comm/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@ApiOperation("提交评论")
@PostMapping("/")
public ResultVO comment(@RequestBody @Validated CommentDTO commentDTO) {
commentService.insComment(commentDTO);
return ResultVO.ok("评论成功!");
}
@ApiOperation("根据文章id获取该文章下所有评论")
@GetMapping("/{id}")
public List<CommentVO> getAllComments(@PathVariable String id) {
List<CommentVO> comments = commentService.findCommentByArticleId(id);
return comments;
}
}
/**
* @description 与评论有关的api
*/
@RestController("adminCommentController")
@RequestMapping("admin/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@ApiOperation("分页展示评论列表")
@GetMapping("/")
public PageInfoVO<CommentItemVO> getComment(
@RequestParam(value = "pageNumber", defaultValue = "1", required = false) Integer pageNumber) {
PageInfoVO<CommentItemVO> pageInfoVO = commentService.findAllComments(pageNumber);
return pageInfoVO;
}
@PutMapping("/")
public ResultVO updArticle(@RequestBody @Validated ArticleDTO articleDTO) {
articleService.updArticle(articleDTO);
return ResultVO.ok("更新文章成功!");
}
@ApiOperation("根据对应文章id删除文章")
@DeleteMapping("/{id}")
public ResultVO delArticleById(@PathVariable String id) {
articleService.delete(id);
return ResultVO.ok("ID为" + id + "的文章删除成功!");
}
@ApiOperation("分页获取文章列表")
@GetMapping("/")
public PageInfoVO<SimpleArticleVO> getPageArticles(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
PageInfoVO<SimpleArticleVO> pageInfoVO = articleService.findByCondition(pageNumber, ADMIN_PAGE_SIZE, null, null);
return pageInfoVO;
}
@ApiOperation("根据查询条件筛选文章")
@PostMapping("/query")
public PageInfoVO<SimpleArticleVO> searchArticles(@RequestBody QueryConditionDTO condition) {
PageInfoVO<SimpleArticleVO> pageInfoVO = articleService.findArticles(condition);
return pageInfoVO;
}
}
/**
* @e-mail 1413979079@qq.com
* @description 拦截器:用于日志打印
*/
@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
@Override
public synchronized boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
/**
* @description 管理员token拦截器
*/
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private ConfigMapper configMapper;
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
return true;
}
String token = req.getHeader("Authorization");
log.info("admin token:" + token);
if (token == null) {
res.setStatus(403);
res.setHeader("Access-Control-Allow-Origin", "*");
return false;
}
ConfigDO cdo = configMapper.findByKey("admin_token");
if (!cdo.getValue().equals(token)) {
res.setStatus(403);
res.setHeader("Access-Control-Allow-Origin", "*");
return false;
}
return true;
}
}
draftDO.setTitle(draftDTO.getTitle());
draftDO.setContent(draftDTO.getContent());
draftDO.setGmtUpdate(System.currentTimeMillis());
draftMapper.updDraft(draftDO);
Map<String, Object> map = new HashMap<>();
map.put("msg", "文章已自动保存,上次保存时间:" + Utils.formatDate(draftDO.getGmtUpdate(), DATE_TIME_PATTERN));
map.put("id", id);
return map;
}
@ApiOperation("根据id删除指定草稿")
@DeleteMapping("/{id}")
public ResultVO get(@PathVariable String id) {
draftMapper.deleteById(id);
return ResultVO.ok("删除成功");
}
}
/**
* @e-mail 1413979079@qq.com
* @description 博客初始化
*/
@RestController
@RequestMapping("/init")
public class InitController {
@Autowired
private ConfigMapper configMapper;
@Autowired
private ConfigService configService;
@GetMapping("/check")
public ResultVO check() {
List<ConfigDO> all = configMapper.findAll();
if (all.isEmpty()) {
@ApiOperation("导入博客数据")
@PostMapping("/import")
public ResultVO importData(@RequestParam("blogData") MultipartFile file) {
try {
ObjectInputStream ois = new ObjectInputStream(file.getInputStream());
BlogData blogData = (BlogData) ois.readObject();
blogService.importData(blogData);
} catch (IOException e) {
log.error("导入博客数据,文件上传失败:{}", e.getMessage());
return ResultVO.error("数据导入失败");
} catch (ClassNotFoundException e) {
log.error("导入博客数据,{}", e.getMessage());
return ResultVO.error("数据导入失败");
}
return ResultVO.ok("数据导入成功");
}
@ApiOperation("修改或插入博客信息")
@PostMapping("/profile")
public ResultVO updProfile(@RequestBody ProfileDTO profileDTO) {
configService.updConfig(profileDTO);
return ResultVO.ok("操作成功");
}
@ApiOperation("获取统计图表的信息")
@GetMapping("/chart")
public Map<String, Object> getArticlesCountByMouth() {
return blogService.countByMonth();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
}
}
/**
* @description 与文章相关的api
*/
@RestController("commArticleController")
@RequestMapping("comm/articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
@Autowired
private ArticleMapper articleMapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@ApiOperation("根据条件分页显示文章")
@GetMapping("/page")
public PageInfoVO<SimpleArticleVO> getPageArticles(
@ApiParam("页码") @RequestParam(value = "pageNumber", defaultValue = "1", required = false) Integer pageNumber,
@ApiParam("约束条件") @RequestParam(required = false) String condition,
@ApiParam("约束条件对应的信息") @RequestParam(required = false) String data
) {
return articleService.findByCondition(pageNumber, DEFAULT_PAGE_SIZE, condition, data);