1Servlet API
1.ServletConfig接口
Web容器启动后会会读取Servlet设置信息,将Servlet类加载并实例化,每一个Servlet设置信息会产生一个ServletConfig对象,而后调用Servlet的init()方法并将ServletConfig对象当作参数传入。
GenericServlet类
GenericServlet接口类同时继承Servlet接口和SevletConfig接口.
1).ServletConfig对象
GenericServlet主要的目的,就是将初始Servlet调用init()方法传入的ServletConfig封装起来。
private transient ServletConfig config;
public void init(ServletConfig config) throw ServletException{
this.config=config;
this.init();
}
public void init() throws ServletException{
}
GenericServlet在实现Servlet的init()方法时,也调用了另一个无参数的init()方法,在编写Servlet时,如果有一些初始动作时,可以重新定义这个无参数的init()方法,而不是直接重新定义有ServletConfig参数的init()方法。
2).使用ServletConfig设置Servlet初始参数
@WebServlet(name="ServletConfigDemo",urlPatterns={"/conf"},
initParams={
@WebInitParam(name="PARAM1",value="VALUE1"),
@WebInitParam(name="PARAM2",value="VALUE2")
` }
)
public class ServletConfigDemo extends HttpServelt(HttpServlet req
HttpServletResponse resp){
private String PARAM1;
private String PARAM2;
//初始化方法中取得初始参数
public void init( ) throws ServeltException{
PARAM1=getServeltConfig().getInitParameter("PARAM1");
PARAM2=getServeltConfig().getInitParameter("PARAM2");
}
...
}
GenericServlet定义了一些方法将ServletConfig封装起来,便于获取设置信息,所以取得Servlet初始参数的代码也可以写为:
@WebServlet(name="ServletConfigDemo",urlPatterns={"/conf"},
initParams={
@WebInitParam(name="PARAM1",value="VALUE1"),
@WebInitParam(name="PARAM2",value="VALUE2")
` }
)
public class ServletConfigDemo extends HttpServelt(HttpServlet req
HttpServletResponse resp){
private String PARAM1;
private String PARAM2;
//初始化方法中取得初始参数
public void init( ) throws ServeltException{
PARAM1=getInitParameter("PARAM1");
PARAM2=getInitParameter("PARAM2");
}
...
}
3)在web.xml中设置Servelt 初始参数
<Servelt>
<Servelt-name>ServletConfigDemo</Servelt-name>
<Servelt-class>cc.ophenhome.ServletConfigDemo</Servelt-class>
<init-param>
<param-name>PARAM1<param-name>
<param-value>VALUE1<param-value>
</init-param>
<init-param>
<param-name>PARAM2<param-name>
<param-value>VALUE2<param-value>
</init-param>
</Servelt>
2使用ServeltContext
1.getRequestDispatcher( )
该方法取得RequestDispatcher实例取得实例之后,就可以进行请求的转发或包含。
context.getRequestDispatcher( " /")
.forward(request,response);
2.getResourcePaths( )
想知道某个目录下有哪些文件
for(String avatar: getServletContext( ).getResourcePaths("/avatars") ) {
avatar= avatar.repalceFirst("/","");
...
}
3.getResourceAsStream( )
读取应用程序中某一个文件内容
InputStream in = getServletContext( ).getResourceAsStream(" ");
OutputSteam out = response.getOutputStream( );
writebytes(in,out);
2. 过滤器
在多个页面需要统一执行的代码,可以通过过滤器的 web 组件来完成
英文 Filter
1) 定义过滤器
@WebFilter(urlPattern="要过滤哪些路径")
class 过滤器类 implements Filter {
// 初始化操作
public void init() { }
// 销毁操作
public void destroy() { }
// 过滤方法 子类对象 子类对象 过滤器链
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain ) throws ... {
// 要统一执行的代码
//chain.doFilter(request, response); // 调用此方法,让请求继续前进
}
}
2) 过滤路径格式
- 精确匹配 /servlet1, 只会进入servlet1之前进入过滤器
- 后缀匹配 *.jsp , 只要请求的后缀是 jsp 结尾的,就会进入过滤器
- 前缀匹配 /user/* , 例如 /user/insert /user/update, 都会经过此过滤器
只要过滤器的路径与目标路径匹配,这个过滤器就会被执行,因此,在请求前进的过程中会经过多个过滤器
顺序和过滤器的名字有关, 按名字排序
3) request和response的类型转换
filter中的request,response 声明的是父类型,有些方法没有,需要转为子类型对象(实际就是子类对象,可以安全转换)
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;
4) 过滤器的应用
-
post 请求的中文乱码,可以采用字符编码过滤器来解决
req.setCharacterEncoding(“解码字符集”);
req.getParameter() -
登录检查过滤器 (见 cookie和 session的代码)
/*
req.getRequestURI 排除一些特殊的路径/user/insert.jsp
重定向到 index.jsp 如果没有加/ 是相对路径
http://localhost:8080/user/index.jsp如果加了 / ,就是相对于主机名和端口号 也就是直接在路径前加 http://localhost:8080
结论:如果路径中有多层目录,建议以 / 写一个完整路径
-
cookie 自动登录过滤器
在 LoginServlet 中登录成功后,补充代码
// 如果勾选了 自动登录
String autoLogin = req.getParameter("autoLogin");
if(autoLogin != null && autoLogin.equals("true")) {
Cookie cookie = new Cookie("up", username + ":" + password);
cookie.setMaxAge(24 * 3600);
resp.addCookie(cookie);
}
在 LoginFilter 过滤器中补充代码:
// 找到 up cookie
Cookie[] cookies = req.getCookies();
Cookie up = null;
for(Cookie c : cookies) {
if (c.getName().equals("up")) {
up = c;
break;
}
}
if(up != null) {
String[] split = up.getValue().split(":");
String name = split[0];
String password = split[1];
// 验证cookie 用户名密码是否正确
User user = userDao.findByUsername(name);
if(user!=null && user.getPassword().equals(password)) {
// 正确了,向 session中存入登录标记并放行
req.getSession().setAttribute("username", username);
chain.doFilter(req, resp);
return;
}
}
在注销时:
// 删除 自动登录 cookie
Cookie up = new Cookie("up", "");
up.setMaxAge(0);
resp.addCookie(up);
3. 监听器
Listener 没有路径,特定事件发生时,会执行监听器代码
- ServletRequestListener 在请求对象初始化和销毁时
- HttpSessionListener 在 session 对象创建后和销毁时
- ServletContextListener application 对象创建和销毁时
public interface ServletContextListener extends EventListener{
public void contextInitialized(ServletContextEvent sce);
public void contextDestroyed(ServletContextEvent sce);
}
- ServletRequestAttributeListener 请求中作用域变量发生改变时
- HttpSessionAttributeListener session 中作用域变量发生改变时
- ServletContextAttributeListener application 中作用域变量发生改变时
public interface ServletContextAttributeListener extends EventListener{
public void attributeAdded(ServletContextAttributeEvent scab);
public void attributeRemoved(ServletContextAttributeEvent scab);
public void attributeReplaced(ServletContextAttributeEvent scab);
}
- HttpSessionActivationListener 在session 钝化(内存存入磁盘)和活化(从磁盘恢复到内存)
session 中存储对象,对象要实现 Serializable 接口 - HttpSessionBindingListener