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。如果有错或更好的建议请指出,谢谢。
|