案例1:分IP统计网站的访问次数
分析
统计不同的IP访问网站的次数,需要在所有资源中执行,这个工作可以放在Filter中。
使用Map<String,Integer>来装载统计数据,整个网站只需要一个map,并存放在ServletContext中。
- Map在监听器中创建(使用监听器:ServletContextListener,在服务器启动时创建,并存储到ServletContext中)
- Ip统计工作在Filter中完成:获取的ip如果存在Map中,就将对应的map值加一,否则添加该ip,并将值设置成1。
实例代码
监听器:AListener.java
public class AListener implements ServletContextListener{
/**
* 启动服务创建ServletContext时启动
* 只调用一次
* @param servletContextEvent
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//创建map用来存放访问统计结果
Map<String,Integer>map=new HashMap<>();
//获得servletcontext对象,并将map存入
ServletContext application=servletContextEvent.getServletContext();
application.setAttribute("map",map);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
过滤器:AFilter.java
@WebFilter(filterName = "AFilter",urlPatterns = "/*")
public class AFilter implements Filter {
private FilterConfig config;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//获得servletContext域中的map
ServletContext application=config.getServletContext();
Map<String,Integer> map= (Map<String, Integer>) application.getAttribute("map");
//获取访问ip
String ip=req.getRemoteAddr();
/**
* 判断map中是否含有该ip
* 如果有 值再加一
* 如果没有,值设置成1
*/
if (map.containsKey(ip)) {
int count = map.get(ip);
map.put(ip,count+1);
}else{
map.put(ip,1);
}
//将map存入application
application.setAttribute("map",map);
//放行
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
this.config=config;
}
}
显示结果界面:show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>显示</title>
</head>
<body>
<h1 align="center">显示结果</h1>
<table align="center" width="60%" border="1">
<%--属性行--%>
<tr>
<th>IP</th>
<th>次数</th>
</tr>
<c:forEach items="${applicationScope.map}" var="entry">
<tr>
<th>${entry.key}</th>
<th>${entry.value}</th>
</tr>
</c:forEach>
</table>
</body>
</html>
效果
案例2 粗粒度权限控制(根据用户名登陆)
RBAC(Role-Based policies Access Control) -> 基于角色的权限控制:例如不同用户的权限不同,可以查看的资源不同。对资操作的权限也不同:增删改查等等。
我们这个案例只是简单的根据登陆名来拦截。
说明:
我们给出三个页面:index.jsp、user.jsp、admin.jsp。
- index.jsp:谁都可以访问,没有限制;
- u.jsp:只有登录用户(包含管理员)才能访问,否则返回登陆界面;
- a.jsp:只有管理员才能访问,否则返回登陆界面;
- login.jsp:登陆界面。
分析:
用户访问登陆界面后,只需要输入登录名,包含user为用户,包含admin为管理员,登陆名保存到session中
AdminFilter拦截a.jsp请求,判断当前请求是否为管理员
UserFilter拦截u.jsp,判断当前请求是否为用户
代码实例
登陆界面login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆</title>
</head>
<body>
${msg}
<form action="<c:url value="/LoginServlet"/>" method="post">
用户名:<input type="text" name="username"/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>
index.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
游客您好,欢迎访问!<br/>
<a href="<c:url value='/index.jsp'/>">游客页面</a><br/>
<a href="<c:url value='/admin/a.jsp'/>">管理员页面</a><br/>
<a href="<c:url value='/user/u.jsp'/>">用户页面</a><br/>
</body>
</html>
a.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>管理您好!</h1><br/>
<a href="<c:url value='/index.jsp'/>">游客页面</a><br/>
<a href="<c:url value='/admin/a.jsp'/>">管理员页面</a><br/>
<a href="<c:url value='/user/u.jsp'/>">用户页面</a><br/>
</body>
</html>
u.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>管理员</title>
</head>
<body>
<h1>用户您好!</h1><br/>
<a href="<c:url value='/index.jsp'/>">游客页面</a><br/>
<a href="<c:url value='/admin/a.jsp'/>">管理员页面</a><br/>
<a href="<c:url value='/user/u.jsp'/>">用户页面</a><br/>
</body>
</html>
LoginServlet.java
@WebServlet(name = "LoginServlet",urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username=request.getParameter("username");
if(username.contains("admin")){//用户名中包含admin,进入管理员页面
//保存管理员账号到session中
request.getSession().setAttribute("admin",username);
}else{//进入用户页面
//保存用户账号到session中
request.getSession().setAttribute("user",username);
}
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
}
AdminFilter.java
public class AdminFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将ServletRequest对象强转成HttpServletRequest
HttpServletRequest request= (HttpServletRequest) req;
//获得session对象
HttpSession session=request.getSession();
String username1= (String) session.getAttribute("admin");
if (username1 == null) {
session.setAttribute("msg","你不是管理员!");
request.getRequestDispatcher("/login.jsp").forward(req,resp);
}else{
chain.doFilter(req, resp);
}
}
public void init(FilterConfig config) throws ServletException {
}
}
UserFilter.java
public class UserFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws ServletException, IOException {
//将ServletRequest对象强转成HttpServletRequest
HttpServletRequest request= (HttpServletRequest) req;
//获得session对象
HttpSession session=request.getSession();
String username1= (String) session.getAttribute("admin");
String username2= (String) session.getAttribute("user");
if (username1!=null||username2!=null) {
chain.doFilter(req, resp);
}else{
session.setAttribute("msg","你是游客,不能访问用户界面!");
request.getRequestDispatcher("/login.jsp").forward(req,resp);
}
}
public void init(FilterConfig config) throws ServletException {
}
}
案例4、解决全站字符乱码(POST和GET中文乱码问题)
在servlet中解决乱码问题方式:
- POST:request.setCharacterEncoding("utf-8");
- GET:String username = request.getParameter(“username”); username = new String(username.getBytes(“ISO-8859-1”), “utf-8”);
分析:
在过滤器中解决POST乱码很简单,只需要添加request.setCharacterEncoding("utf-8");
但是对于GET乱码就很麻烦,我们不可能一一去处理每个中文参数。这里可以使用装饰者模式参考:设计模式—装饰者模式
在过滤器中将request对象进行调包:
- 写一个request装饰类:增强getParameter方法,对get请求进行编码处理
- 放行时传递我们自己的request对象
说明:
encoding.jsp页面包含get请求链接和post请求链接,都向服务器发送中文。
encodingServlet.java取出中文,显示在客户端
代码实现
encoding.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>编码显示</title>
</head>
<body>
<a href="<c:url value='/EncodingServlet?username=张三'/>">点击这里</a><br/>
<form action="<c:url value='/EncodingServlet'/>">
<input type="text" name="username" value="李四"/>
<input type="submit" value="点击"/><br/>
</form>
</body>
</html>
encodingServlet.java
@WebServlet(name = "EncodingServlet",urlPatterns = "/EncodingServlet")
public class EncodingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置相应编码处理
response.setContentType("text/html;charset=utf-8");
String username=request.getParameter("username");
response.getWriter().println(username);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置相应编码处理
response.setContentType("text/html;charset=utf-8");
String username=request.getParameter("username");
response.getWriter().println(username);
}
}
EncodingReqest.java
/**
* HttpServletRequestWrapper 类实现了HttpServletRequest接口,把我们把所有的方法都处理了依靠底层对象
*/
public class EncodingRequest extends HttpServletRequestWrapper {
private String charset;
//创建底层依赖对象
private HttpServletRequest request;
public EncodingRequest(HttpServletRequest request,String charset){
super(request);
this.request=request;
this.charset=charset;
}
/**
* 在这个对每个参数进行GET编码处理
* @param name
* @return
*/
@Override
public String getParameter(String name) {
// 获取参数
String value = request.getParameter(name);
if(value == null) return null;//如果为null,直接返回null
try {
// 对参数进行编码处理后返回
return new String(value.getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public Map getParameterMap() {
Map<String,String[]> map = request.getParameterMap();
if(map == null) return map;
// 遍历map,对每个值进行编码处理
for(String key : map.keySet()) {
String[] values = map.get(key);
for(int i = 0; i < values.length; i++) {
try {
values[i] = new String(values[i].getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
// 处理后返回
return map;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
for(int i = 0; i < values.length; i++) {
try {
values[i] = new String(values[i].getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return values;
}
}
EncodingFilter.java
/**
* 全站乱码处理
*/
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//处理POST请求编码
req.setCharacterEncoding("utf-8");
HttpServletRequest request= (HttpServletRequest) req;
if (request.getMethod().equalsIgnoreCase("post")) {
//直接放行
chain.doFilter(req, resp);
}else if(request.getMethod().equalsIgnoreCase("get")){
//如果是get请求,使用我们自定义的EncodingRequest来处理编码
EncodingRequest er=new EncodingRequest(request);
chain.doFilter(er,resp);
}
}
public void init(FilterConfig config) throws ServletException {
}
}