1. 总述:
这是我在寝室写完的第一个博客项目,没有使用博客主题搭建,页面都是自己写的,花了挺多心思的。
项目除了基本的博客、分类、标签、归档模块以外,还有留言、资源库、音乐秀、跑步秀、图片库等模块,这些都是我后来想到结合我个人兴趣然后去写的。
整个前后端代码几乎一大半都是自己写的,没有使用第三方技术(项目简单),这个过程让我收获到了很多,以后继续加油。
1.1 主要使用技术
- 前端:Semantic UI框架,Bootstrap 框架,Layui框架,jquery。
- 后端:SpringBoot + MyBatis-Plus + Thymeleaf 引擎模板
- 数据库:Mysql
- 整合技术:JMS邮件
1.2 主要技术点
- 异步任务
- 定时任务
- 邮件任务
- session、cookie使用
- 统一异常处理
- 登录拦截
- 自定义日志注解
2. 部分效果图:
3. 部分代码
- 博客controller
@Slf4j @Controller public class UserBlogController { @Autowired private BlogService blogService; //整个博客首页 @GetMapping @WebLog(description = "用户进入网站介绍首页") public String main(Model model, HttpServletRequest request){ return blogService.main(model,request); } //去前台博客博客首页 @GetMapping("/user") @WebLog(description = "用户进入首页") public String uindex(HttpSession session, Model model,HttpServletResponse response,HttpServletRequest request, @RequestParam(value = "current",defaultValue = "1")Integer current, @RequestParam(value = "pageSize",defaultValue = "9")Integer pageSize){ return blogService.uindex(session,model,response,request,current,pageSize); } //访客查看博客详情 @GetMapping("/user/blog/{id}") @WebLog(description = "用户查看博客详情") public String blog(@PathVariable("id") Long id,Model model,HttpServletRequest request){ return blogService.userGetBlogById(id,model,request); } //通过博客名字搜索博客id和名字 @ResponseBody @PostMapping("/blog") @WebLog(description = "用户全局搜索博客") public Msg blog(String title){ return blogService.blog(title); } //博客相关信息 @ResponseBody @GetMapping("/footer/blogMessage") public Msg blogMessage(){ return Msg.success().add("blogcount",blogService.blogCount()) .add("viewcount",blogService.viewCount()) .add("visitorcount",blogService.visitorCount()) .add("commentcount",blogService.commentCount()) .add("messagecount",blogService.messageCount()); } //点赞增加 @ResponseBody @PostMapping("/user/blog/likes/add") @WebLog(description = "用户点赞博客") public Msg add(Long id){ return blogService.addLike(id); } }
- 统一异常处理
@Slf4j @ControllerAdvice public class ExceptionController { @Autowired private SendEmail sendEmail; @Autowired JavaMailSender mailSender; @Autowired TemplateEngine templateEngine; @ExceptionHandler(Exception.class) public ModelAndView excetionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception { log.error("Request URL: {},Exception: {}",request.getRequestURL(),e); String title="网站发生错误!!!"; StackTraceElement[] trace = e.getStackTrace(); String to="xxxxxxxxx"; String content=arrayToString(trace); Context context = new Context(); context.setVariable("url",request.getRequestURL()); context.setVariable("status",response.getStatus()); context.setVariable("message",e.getMessage()); context.setVariable("detail",content); String process=templateEngine.process("errorMail",context); sendEmail.sendHtmlMail(to,title,process,mailSender); if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) { throw e; } ModelAndView mv=new ModelAndView(); mv.addObject("url",request.getRequestURL()); mv.addObject("exception",e); mv.setViewName("error/error"); return mv; } public static String arrayToString(StackTraceElement[] arr){ String content=new String(); for (int i=0;i<arr.length;i++){ content += arr[i]+"\n"; } return content; } }
- 自定义日志注解
@Aspect @Component @Slf4j public class LogAspect { /** 换行符 */ private static final String LINE_SEPARATOR = System.lineSeparator(); /** 以自定义 @WebLog 注解为切点 */ @Pointcut("@annotation(com.example.my.aspect.WebLog)") public void webLog() {} /** * 在切点之前织入 * @param joinPoint * @throws Throwable */ @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 开始打印请求日志 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取 @WebLog 注解的描述信息 String methodDescription = getAspectLogDescription(joinPoint); // 打印请求相关参数 log.warn("========================================== Start =========================================="); // 打印描述信息 log.warn("Description : {}", methodDescription); // 打印请求的 IP log.warn("IP : {}", request.getRemoteAddr()); /*// 打印请求 url log.warn("URL : {}", request.getRequestURL().toString()); // 打印请求入参 //log.info("Request Args : {}", new Gson().toJson(joinPoint.getArgs())); // 打印 Http method log.warn("HTTP Method : {}", request.getMethod()); // 打印调用 controller 的全路径以及执行方法 log.warn("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());*/ } /** * 在切点之后织入 * @throws Throwable */ @After("webLog()") public void doAfter() throws Throwable { // 接口结束后换行,方便分割查看 log.warn("=========================================== End ===========================================" + LINE_SEPARATOR); } /** * 环绕 * @param proceedingJoinPoint * @return * @throws Throwable */ /* @Around("webLog()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = proceedingJoinPoint.proceed(); // 打印出参 log.warn("Response Args : {}", new Gson().toJson(result)); // 执行耗时 log.warn("Time-Consuming : {} ms", System.currentTimeMillis() - startTime); return result; }*/ /** * 获取切面注解的描述 * * @param joinPoint 切点 * @return 描述信息 * @throws Exception */ public String getAspectLogDescription(JoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); StringBuilder description = new StringBuilder(""); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { description.append(method.getAnnotation(WebLog.class).description()); break; } } } return description.toString(); } }
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface WebLog { /** * 日志描述信息 * * @return */ String description() default ""; }
- 定时任务
@Service public class Records { @Autowired private VisitorMapper visitorMapper; @Autowired private BlogMapper blogMapper; @Autowired private CommentMapper commentMapper; @Autowired private MessageMapper messageMapper; //昨日访客新增,访问量新增,评论量新增,留言量新增 //corn 秒 分 时 日 月 周几 @Scheduled(cron="0 1 0 * * ?") //凌晨一点获取前一周的数据 public void update(){ updateRecords(1); updateRecords(2); updateRecords(3); updateRecords(4); updateRecords(5); updateRecords(6); updateRecords(7); } public int updateRecords(Integer num ){ Key key = get(num); int visitor = key.getVisitor(); int blogview=key.getView() ; int comment=key.getComment() ; int message= key.getMessage(); int i = visitorMapper.updateRecords(key, -num,visitor, blogview , comment , message); return i; } public Key get(Integer num){ DateTime dt = new DateTime(); String yes = dt.minusDays(num).toString("yyyy-MM-dd"); int visitor = visitorMapper.selectCount(new QueryWrapper<Visitor>().like("create_time", yes)); int blogview = blogMapper.yesviewCount(yes); int comment = commentMapper.selectCount(new QueryWrapper<Comment>().like("create_time", yes)); int message = messageMapper.selectCount(new QueryWrapper<Message>().like("create_time", yes)); Key k=new Key(); k.setVisitor(visitor); k.setView(blogview); k.setComment(comment); k.setMessage(message); return k; } }
4. 总结
项目大概就是这样子,大二结束我写完这个项目知道了自己的不足也收获到了很多,后面继续加油,欢迎大家来访问留言,==》》(https:tgcsblog.top)~ 欢迎来到我的小栈 ~电脑访问效果更好哦。也可到b站查看动态效果视频:集技术、艺术、运动于一身的个人博客。_哔哩哔哩_bilibili。如果有错或更好的建议请指出,谢谢。