如何在无表单且直接运行JSP时从Servlet传递数据至JSP?
嘿,我明白你现在的困惑——你在Servlet里查了数据库、把数据塞到request里,然后通过Dispatcher转发给JSP,这时候能拿到数据;但直接点开JSP或者输入JSP的URL,啥数据都没有,连JSTL都不管用。其实核心原因特别简单:直接运行JSP的时候,你的Servlet根本没被调用啊!
当你直接访问JSP的URL,服务器只会编译执行JSP本身,不会触发对应的Servlet逻辑——那Servlet里查的数据库数据、设置的request属性,自然不会出现在当前的请求里,JSP当然读不到。
那能不能实现“直接访问JSP就展示数据库数据”?当然可以!但得换个思路,让原本在Servlet里的逻辑,在JSP被访问时自动跑起来。下面给你几个靠谱的方案:
方案1:让JSP自动转发到Servlet(简单粗暴)
你可以在JSP的最顶部加一小段代码,让它先跳转到你的Servlet,等Servlet查完数据、塞好属性,再转发回这个JSP。这样用户直接访问JSP URL时,就会自动触发Servlet的逻辑。示例代码:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% // 加个判断,避免无限循环——如果request里已经有数据,说明是Servlet转发过来的,直接渲染页面 if (request.getAttribute("dbData") == null) { // 替换成你的Servlet的映射路径 request.getRequestDispatcher("/your-servlet-mapping").forward(request, response); return; // 停止当前JSP的后续执行,不然会重复渲染 } %> <!-- 下面是你的页面内容,用JSTL展示数据就行 --> <c:forEach var="item" items="${dbData}"> <div>${item.title}:${item.content}</div> </c:forEach>
这个方案的好处是改动小,不需要额外写太多代码,但要注意Servlet的路径要写对,而且那个判断一定要加,不然会陷入无限转发的死循环。
方案2:用Filter拦截JSP请求(更规范的MVC做法)
如果想让代码更干净、符合MVC的分离原则,推荐写一个Filter(过滤器),拦截所有访问目标JSP的请求,在Filter里执行数据库查询、把数据塞到request里,再让请求继续走到JSP。这样数据加载的逻辑和页面完全分开,后期维护也方便。
示例Filter代码:
import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.List; @WebFilter(urlPatterns = "/your-target.jsp") // 拦截目标JSP的请求 public class DataLoadFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; // 这里调用你的数据库服务,获取数据 List<YourDataModel> dbData = YourDatabaseService.getFromDB(); // 把数据放到request属性里,JSP就能通过EL表达式拿到 req.setAttribute("dbData", dbData); // 让请求继续往下走,到JSP页面 chain.doFilter(request, response); } // init和destroy方法如果不需要可以留空或者简单实现 @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
配置好这个Filter之后,用户每次访问那个JSP,都会先经过Filter加载数据,再渲染页面,完美实现你的需求。
方案3:直接在JSP里写数据库逻辑(不推荐,但能用)
如果你实在不想碰Servlet或Filter,也可以直接在JSP里写Java代码调用数据库查询,但我真的不建议这么做——这会把业务逻辑和页面视图混在一起,代码难调试、难复用,页面也会变得臃肿不堪。不过还是给你个示例,你自己权衡:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.List" %> <%@ page import="com.yourpackage.YourDataModel" %> <%@ page import="com.yourpackage.YourDatabaseService" %> <% // 直接在JSP里调用数据库服务 List<YourDataModel> dbData = YourDatabaseService.getFromDB(); request.setAttribute("dbData", dbData); %> <c:forEach var="item" items="${dbData}"> <p>${item.name}</p> </c:forEach>
最后再划个重点
直接跑JSP拿不到Servlet数据的本质就是:Servlet没执行,数据从来没被放进请求里。要实现直接访问JSP展示数据,核心就是让数据加载逻辑在JSP被访问时自动触发——优先推荐Filter的方案,其次是JSP转发的方式,尽量别用第三种把逻辑写在JSP里的做法。
内容的提问来源于stack exchange,提问作者arjunhitachi

