对于带有 JSP 和 servlet 的非常简单的 MVC,过滤器的功能是什么?
下面的示例中有一个控制器 servlet,然后每个 JSP 都呈现出不同的视图。 Servlet 主要与模型(包含用户列表的属性文件)进行交互。但是,
login.jsp
会改变令牌,它是一个会话 bean。
我意识到通常 Spring、facelets 或其他一些框架会发挥作用——我只是在摸索。
servlet使用过滤器是正确的过滤器用法吗?我不确定过滤器将如何在这里发挥作用——除了可以从控制器 servlet 中提取要分派到的 JSP 的“逻辑”并单独存在于过滤器中......?
JSP 不需要访问过滤器,因为所有调度都是通过 servlet 完成的(?)。
servlet:
package net.bounceme.dur.servlets;
import filter.PropertiesReader;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/controller")
public class Controller extends HttpServlet {
private static final Logger log = Logger.getLogger(Controller.class.getName());
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("controller processing request..");
String jsp = dispatcherLogic(request.getSession());
request.getRequestDispatcher("/WEB-INF/" + jsp).forward(request, response);
}
private String dispatcherLogic(HttpSession session) {
Properties properties = PropertiesReader.getProps();
MyToken token = (MyToken) session.getAttribute("token");
if (token != null) {
token.setAuthenticated(properties.containsValue(token.getName()));
} else {
token = new MyToken();
}
log.info(token.toString());
session.setAttribute("token", token);
if (token.isAuthenticated()) {
return "success.jsp";
} else {
if (token.isAttemptedLogin()) {
return "fail.jsp";
} else {
return "login.jsp";
}
}
}
private String dispatcherLogic0(HttpSession session) {
Map<String, String> p = PropertiesReader.getPropsAsMap();
Enumeration<String> names = session.getAttributeNames();
for (String s : Collections.list(names)) {
log.info(s);
}
MyToken t = (MyToken) session.getAttribute("token");
for (String s : p.keySet()) {
// t.getName() = p.containsValue(s);
}
return "hello.jsp"; //always to hello page for now
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "controller";
}
}
过滤器:
package net.bounceme.dur.filter;
import filter.PropertiesReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Properties;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class AuthenticateFilter implements Filter {
private static final Logger log = Logger.getLogger(AuthenticateFilter.class.getName());
private FilterConfig filterConfig = null;
public AuthenticateFilter() {
}
private void doBeforeProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException {
log.info("do before processing..");
}
private void doAfterProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException {
log.info("do after processing");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("do filter");
}
public FilterConfig getFilterConfig() {
return (this.filterConfig);
}
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
@Override
public void destroy() {
}
private void props() {
log.info("properties file:");
Properties properties = PropertiesReader.getProps();
StringBuilder sb = new StringBuilder();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
sb.append("\n" + key + " => " + value);
}
log.info(sb.toString());
}
@Override
public void init(FilterConfig filterConfig) {
log.info("init");
this.filterConfig = filterConfig;
if (filterConfig != null) {
log.info("SessionCheckFilter:Initializing filter");
} else {
log.warning("null filterConfig");
}
props();
}
@Override
public String toString() {
if (filterConfig == null) {
return ("SessionCheckFilter()");
}
StringBuilder sb = new StringBuilder("SessionCheckFilter(");
sb.append(filterConfig);
sb.append(")");
return (sb.toString());
}
private void sendProcessingError(Throwable t, ServletResponse response) {
log.info("send processing error");
String stackTrace = getStackTrace(t);
if (stackTrace != null && !stackTrace.equals("")) {
try {
response.setContentType("text/html");
try (PrintStream ps = new PrintStream(response.getOutputStream()); PrintWriter pw = new PrintWriter(ps)) {
pw.print("<html>\n<head>\n<title>Error</title>\n</head>\n<body>\n"); //NOI18N
pw.print("<h1>The resource did not process correctly</h1>\n<pre>\n");
pw.print(stackTrace);
pw.print("</pre></body>\n</html>"); //NOI18N
}
response.getOutputStream().close();
} catch (Exception ex) {
}
} else {
try {
try (PrintStream ps = new PrintStream(response.getOutputStream())) {
t.printStackTrace(ps);
}
response.getOutputStream().close();
} catch (Exception ex) {
}
}
}
public static String getStackTrace(Throwable t) {
String stackTrace = null;
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.close();
sw.close();
stackTrace = sw.getBuffer().toString();
} catch (Exception ex) {
}
log.warning(stackTrace);
return stackTrace;
}
}
登录令牌:
package net.bounceme.dur.servlets;
import java.util.logging.Logger;
public class MyToken {//should probably be immutable...
private static Logger log = Logger.getLogger(MyToken.class.getName());
private String name = "nemo";
private String role = "captain";
private String password = "abc";
private boolean authenticated = false;
private boolean attemptedLogin = false;
public MyToken() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isAuthenticated() {
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
public boolean isAttemptedLogin() {
return attemptedLogin;
}
public void setAttemptedLogin(boolean attemptedLogin) {
this.attemptedLogin = attemptedLogin;
}
@Override
public String toString() {
return name + authenticated + attemptedLogin;
}
}
servlet 不与过滤器交互。事实上,它甚至不知道是否使用了过滤器(除了副作用)。顺便说一句,你的
AuthenticateFilter.doFilter
很糟糕。如果您在 Web 应用程序中安装这样的过滤器,它将阻止所有内容,因为它永远不会传递到过滤器链!
过滤器的逻辑如下
servlet container prepares ServletRequest and ServletResponses objects and pass them to a *filter chain*
first filter optional pre-processing pass down to next in chain
second filter pre-processing
...
Servlet processing
...
second filter post-processing
first filter optional post processing
servlet container pass (end of) data to client
doFilter
方法很经典:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// optional pre-processing
// optionaly return immediately to by-pass other filters and servlet processing
chain.doFilter(request, response); // pass down to next filter or to servlet
// if last filter in chain
// optional post-processing
}