在web项目中,首页的很多内容都需要从数据库中来获取,但是默认初始加载页面并不会加载出来数据库中的数据,这时,我们需要对数据进行 “预加载”
一 设置初始页面ResultMapping @Controller@RequestMapping("/")public class BookController { @Autowired private CategoryService categoryService; public String toIndex(HttpServletRequest httpServletRequest){ List<Category> categorys = categoryService.listCategory(); System.out.println(categorys); httpServletRequest.getSession().getServletContext().setAttribute("categorys",categorys); return "index"; }}
如果使用这种方式实现,当其他页面访问首页时,填写访问地址会非常不方便,如何改进呢?使用 window.location.href重定位
二 window.location.href现在,访问首页数据的controller变成了这样
@Controller@RequestMapping("home")public class BookController { @Autowired private CategoryService categoryService; @RequestMapping("index") public String toIndex(HttpServletRequest httpServletRequest){ List<Category> categorys = categoryService.listCategory(); System.out.println(categorys); httpServletRequest.getSession().getServletContext().setAttribute("categorys",categorys); return "index"; }}在index.jsp中,我们编写这样一段代码
<script>window.onload = function(){ window.location.href = "${pageContext.request.contextPath}/home/index"; }</script>如果用jquery,代码更简洁~
<script> $(function () { window.location.href = "${pageContext.request.contextPath}/home/index"; })</script>这样设置,在页面加载之初,就会访问"${pageContext.request.contextPath}/home/index"这个路径,从而也就实现了数据的预加载
三 <jsp:forward page="后台需要接收的请求"></jsp:forward>
index.jsp作为首页,无法加载需要的页面数据,那么可以让index.jsp不作为展示数据用,用index.jsp直接跳转其他页面;
index.jsp里加<jsp:forward page="SSM后台接收的请求"></jsp:forward>,携带数据跳转到真正的首页。
四 监听器实现在传统javaweb中,我们可以使用监听器来实现页面数据预加载
@WebListenerpublic class ApplicationListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent sce) { // 监听器销毁时调用该方法 } public void contextInitialized(ServletContextEvent sce) { // 监听器初始化调用该方法 //1.获取application对象 ServletContext application = sce.getServletContext(); //2.查询公告信息存储到application对象中 ReportServiceImpl reportServiceImpl = new ReportServiceImpl(); List<Report> list = reportServiceImpl.listReport(); application.setAttribute("reports", list); //3.查询所有的书籍信息存储到application对象中 //4.查询一级分类以及二级分类信息存储到application对象中 }}如果我们在ssm中使用监听器,利用IOC的特性,代码变成了这个样子
@WebListenerpublic class ApplicationListener implements ServletContextListener { @Autowired private ReportService reportService; public void contextDestroyed(ServletContextEvent sce) { // 监听器销毁时调用该方法 } public void contextInitialized(ServletContextEvent sce) { // 监听器初始化调用该方法 //1.获取application对象 ServletContext application = sce.getServletContext(); //2.查询公告信息存储到application对象中 List<Report> list = reportService.listReport(); application.setAttribute("reports", list); //3.查询所有的书籍信息存储到application对象中 //4.查询一级分类以及二级分类信息存储到application对象中 }}报错了!以上代码在项目启动时会抛出空指针异常!
原因是在ssm中,我们使用依赖注入的方式来操作对象,spring容器会帮助我们管理,监听器的生命周期是由servlet容器(例如tomcat)管理的,项目启动时上例中的ConfigListener是由servlet容器实例化并调用其contextInitialized方法,而servlet容器并不认得@Autowired注解,因此导致ConfigService实例注入失败。
如何解决呢?
这就需要用到spring为我们提供的WebApplicationContextUtils工具类,该工具类的作用是获取到spring容器的引用,进而获取到我们需要的bean实例。
public class PageListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // 监听器初始化调用该方法 //1.获取application对象 System.out.println("listen调用"); ServletContext application = sce.getServletContext();// //2.查询公告信息存储到application对象中 ReportServiceImpl reportService = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(ReportServiceImpl.class); List<Report> list = reportService.listReport(); application.setAttribute("reports", list); //3.查询所有的书籍信息存储到application对象中 //4.查询一级分类以及二级分类信息存储到application对象中 } @Override public void contextDestroyed(ServletContextEvent sce) { }}以上代码有一个前提,那就是servlet容器在实例化ConfigListener并调用其方法之前,要确保spring容器已经初始化完毕!而spring容器的初始化也是由Listener(ContextLoaderListener)完成,因此只需在web.xml中先配置初始化spring容器的Listener,然后在配置自己的Listener,配置如下
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener> <listener> <listener-class>自己的路径</listener-class></listener>