在上周我们已经完成了新闻的后台管理部分以及用户浏览界面的分类、标签和主页,今天来实现界面上的归档功能
从静态界面的设计上我们可以看到,归档是实现了不同年份新闻的分类
归档功能实现
1、设计NewRepository
我们可以直接在IDEA中链接数据库,为了实现归档功能中的新闻按照年份分类,我们可以现在数据库中进行sql命令操作试验。
在console部分输入select命令:
select date_format(n.update_time,'%Y') from t_news n group by date_format(n.update_time,'%Y') order by date_format(n.update_time,'%Y') desc;
select * from t_news n where date_format(n.update_time,'%Y')=2020;
原先新闻数据已有如下年份:
运行后,效果如下:
已经对年份进行分类,并降序排序
第二条是寻找对应年份的新闻:
得到理想效果后,我们回到NewRepository中定义方法接口:
//select date_format(n.update_time,'%Y') from t_news n group by date_format(n.update_time,'%Y') order by date_format(n.update_time,'%Y') desc
@Query("select function('date_format',n.updateTime,'%Y') as year from News n group by year order by year desc")
List<String> findGroupYear();
@Query("select n from News n where function('date_format',n.updateTime,'%Y')= ? 1")
List<News> findByYear(String year);
2、在NewService中定义方法
Map<String,List<News>> archiveNew();
在NewServiceImpl中进行实现:
@Override
public Map<String, List<News>> archiveNew() {
List<String> years=newRepository.findGroupYear();
//HashMap无序,但是我们需要排序的年份,因此不用HashMap而用LinkedHashMap,按照添加的顺序进行遍历
Map<String,List<News>> map=new LinkedHashMap<>();
for(String year:years){
map.put(year,newRepository.findByYear(year));
System.out.println(year);
}
return map;
}
3、接下来创建一个新的Controller,ArchiveShowController,在里面进行具体的操作
@Controller
public class ArchiveShowController {
@Autowired
private NewService newService;
@GetMapping("/archives")
public String archives(Model model){
model.addAttribute("archiveMap",newService.archiveNew());
return "archives";
}
}
归档功能演示
进入归档界面,可以看到按年份归档的新闻还有总篇数,具体点击某一篇新闻的标题,就可以进入新闻详情页。
异常事件处理
1、建一个与dao、service等包同级的类:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{
public NotFoundException(){
}
public NotFoundException(String message){
super(message);
}
public NotFoundException(String message,Throwable cause){
super(message, cause);
}
}
此类中不进行异常的具体处理
2、再新建一个与dao、service等包同级的handler包,构建新的类:
@ControllerAdvice //实现对全局异常进行处理
public class ControllerExceptionHandler {
}
继续完善其中的内容:
@ControllerAdvice //实现对全局异常进行处理
public class ControllerExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ExceptionHandler
public ModelAndView exceptionhandler(HttpServletRequest request,Exception e) throws Exception{
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;
}
}
演示
当我们直接跳过登录部分,进入页面,就会出现异常报错信息:
拦截器
介绍
之前ssm项目中写过一个过滤器和servlet写在一处,使得用户必须通过登录进入界面,不能直接通过网页路径;
在此次SpringBoot项目中,我们尝试使用拦截器。
拦截器:
- 依赖web框架
- 面向切面编程(AOP)
构建拦截器
1、构建一个跟dao、service同级的Interceptor包,针对登陆部分的拦截,构建LoginInterceptor类
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(request.getSession().getAttribute("user")==null){
response.sendRedirect("/admin");//不允许不登陆就进入界面
return false;
}
return true;
}
}
2、构建WevConfig类进行配置部署
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin")
.excludePathPatterns("/admin/login");
}
}
这样一来,若是我们直接进入localhost:8080/admin/types网页,则会被拦截,转而回到admin也就是登陆界面。