今天帮同学看传智写聊天室源码时,在了解了该聊天室大致的结构之后,总结出了一个很不错的工具类!更准确的说是一段写得很优秀的源码!也解答了我长时间以来的疑惑!源代码如下:
1 package cn.itcast.utils; 2 import java.io.IOException; 3 import java.lang.reflect.Method; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class BaseServlet extends HttpServlet { 11 /* 12 * 它会根据请求中的method参数,来决定调用本类的哪个方法 13 */ 14 protected void service(HttpServletRequest req, HttpServletResponse res) 15 throws ServletException, IOException { 16 req.setCharacterEncoding("UTF-8"); 17 res.setContentType("text/html;charset=utf-8"); 18 // 例如:http://localhost:8080/demo1/xxx?method=login 19 String methodName = req.getParameter("method");// 它是一个方法名称 20 // 当没用指定要调用的方法时,那么默认请求的是execute()方法。 21 if(methodName == null || methodName.isEmpty()) { 22 methodName = "execute"; 23 } 24 Class c = this.getClass(); 25 try { 26 // 通过方法名称获取方法的反射对象 27 Method m = c.getMethod(methodName, HttpServletRequest.class, 28 HttpServletResponse.class); 29 // 反射方法目标方法,也就是说,如果methodName为add,那么就调用add方法。 30 String result = (String) m.invoke(this, req, res); 31 // 通过返回值完成请求转发 32 if(result != null && !result.isEmpty()) { 33 req.getRequestDispatcher(result).forward(req, res); 34 } 35 } catch (Exception e) { 36 throw new ServletException(e); 37 } 38 } 39 }
1 package cn.itcast.action; 2 import java.io.IOException; 3 import java.util.Date; 4 import java.util.Map; 5 6 import javax.servlet.ServletContext; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession; 10 import org.apache.commons.beanutils.BeanUtils; 11 import cn.itcast.service.UserService; 12 import cn.itcast.utils.BaseServlet; 13 import cn.itcast.vo.User; 14 public class UserServlet extends BaseServlet { 15 /** 16 * 检查session是否过期 17 * @throws IOException 18 */ 19 public String check(HttpServletRequest req,HttpServletResponse resp) throws IOException{ 20 // 从session中获得用户的信息 21 User existUser = (User) req.getSession().getAttribute("existUser"); 22 // 判断session中的用户是否过期 23 if(existUser == null){ 24 // 登录的信息已经过期了! 25 resp.getWriter().println("1"); 26 }else{ 27 // 登录的信息没有过期 28 resp.getWriter().println("2"); 29 } 30 return null; 31 } 32 33 /** 34 * 退出聊天室 35 * @throws IOException 36 */ 37 public String exit(HttpServletRequest request,HttpServletResponse response) throws IOException{ 38 // 获得session对象 39 HttpSession session = request.getSession(); 40 // 将session销毁. 41 session.invalidate(); 42 // 页面转向. 43 response.sendRedirect(request.getContextPath()+"/index.jsp"); 44 return null; 45 } 46 47 /** 48 * 发送聊天内容 49 * @throws IOException 50 */ 51 public String sendMessage(HttpServletRequest req,HttpServletResponse resp) throws IOException{ 52 // 1.接收数据 。 53 System.out.println("sendMessage invoke...."); 54 String from = req.getParameter("from"); // 发言人 55 String face = req.getParameter("face"); // 表情 56 String to = req.getParameter("to"); // 接收者 57 String color = req.getParameter("color"); // 字体颜色 58 String content = req.getParameter("content"); // 发言内容 59 // 发言时间 正常情况下使用SimpleDateFormat 60 String sendTime = new Date().toLocaleString(); // 发言时间 61 // 获得ServletContext对象. 62 ServletContext application = getServletContext(); 63 // 从ServletContext中获取消息 64 String sourceMessage = (String) application.getAttribute("message"); 65 // 拼接发言的内容:xx 对 yy 说 xxx 66 sourceMessage += "<font color='blue'><strong>" + from 67 + "</strong></font><font color='#CC0000'>" + face 68 + "</font>对<font color='green'>[" + to + "]</font>说:" 69 + "<font color='" + color + "'>" + content + "</font>(" 70 + sendTime + ")<br>"; 71 // 将消息存入到application的范围 72 application.setAttribute("message", sourceMessage); 73 return getMessage(req, resp); 74 } 75 76 /** 77 * 获取消息的方法 78 * @throws IOException 79 */ 80 public String getMessage(HttpServletRequest req,HttpServletResponse resp) throws IOException{ 81 String message = (String) getServletContext().getAttribute("message"); 82 if(message != null){ 83 resp.getWriter().println(message); 84 } 85 return null; 86 } 87 /** 88 * 踢人的功能 89 * @throws IOException 90 */ 91 public String kick(HttpServletRequest req,HttpServletResponse resp) throws IOException{ 92 // 1.接收参数 93 int id = Integer.parseInt(req.getParameter("id")); 94 // 2.踢人:从userMap中将用户对应的session销毁. 95 // 获得userMap集合(在线列表) 96 Map<User, HttpSession> userMap = (Map<User, HttpSession>) getServletContext() 97 .getAttribute("userMap"); 98 // 获得这个用户对应的session.如何知道是哪个用户呢? id已经传递过来.去数据库中查询. 99 // 重写user的equals 和 hashCode 方法 那么只要用户的id相同就认为是同一个用户. 100 User user = new User(); 101 user.setId(id); 102 // 从map集合中获得用户的对应的session 103 HttpSession session = userMap.get(user); 104 // 销毁session 105 session.invalidate(); 106 // 重定向到页面 107 resp.sendRedirect(req.getContextPath()+"/main.jsp"); 108 return null; 109 } 110 111 /** 112 * 登录的功能 113 */ 114 public String login(HttpServletRequest req,HttpServletResponse resp){ 115 // 接收数据 116 Map<String, String[]> map = req.getParameterMap(); 117 User user = new User(); 118 // 封装数据 119 try { 120 BeanUtils.populate(user, map); 121 // 调用Service层处理数据 122 UserService us = new UserService(); 123 User existUser = us.login(user); 124 if (existUser == null) { 125 // 用户登录失败 126 req.setAttribute("msg", "用户名或密码错误!"); 127 return "/index.jsp"; 128 } else { 129 // 用户登录成功 130 // 第一个BUG的解决:第二个用户登录后将之前的session销毁! 131 req.getSession().invalidate(); 132 133 // 第二个BUG的解决:判断用户是否已经在Map集合中,存在:已经在列表中.销毁其session. 134 // 获得到ServletCOntext中存的Map集合. 135 Map<User, HttpSession> userMap = (Map<User, HttpSession>) getServletContext() 136 .getAttribute("userMap"); 137 // 判断用户是否已经在map集合中' 138 if(userMap.containsKey(existUser)){ 139 // 说用map中有这个用户. 140 HttpSession session = userMap.get(existUser); 141 // 将这个session销毁. 142 session.invalidate(); 143 } 144 // 使用监听器:HttpSessionBandingListener作用在JavaBean上的监听器. 145 req.getSession().setAttribute("existUser", existUser); 146 ServletContext application = getServletContext(); 147 String sourceMessage = ""; 148 if (null != application.getAttribute("message")) { 149 sourceMessage = application.getAttribute("message") 150 .toString(); 151 } 152 sourceMessage += "系统公告:<font color='gray'>" 153 + existUser.getUsername() + "走进了聊天室!</font><br>"; 154 application.setAttribute("message", sourceMessage); 155 156 resp.sendRedirect(req.getContextPath() + "/main.jsp"); 157 return null; 158 } 159 } catch (Exception e) { 160 e.printStackTrace(); 161 } 162 return null; 163 } 164 }
这两个类结构写的蛮清楚的!一旦有请求过来,比如说:http:8080//localhost/项目名/User/method=login!当到达UserServlet时就会执行service方法。接下来所做的工作就是得到该类的类加载器,并根据方法名(为null时默认调用execute方法)调用对应的方法!这样就实现了UserServlet类处理多个Action请求的目的!说到这里,衷心觉得这段代码写得蛮好的!![工具类积累(二)—— 一个Servlet处理多个URL请求 - 薛定谔的猫 - 薛定谔的猫 工具类积累(二)—— 一个Servlet处理多个URL请求 - 薛定谔的猫 - 薛定谔的猫]()

想到这里,我突然想到了Struts2!它的模式似乎也是这样!在一个类中处理多个请求!看了上面一段代码!突然就形成了一个想法,或者说猜测吧!(没看源码,也没得到验证)现在我就基于上面的代码思路来简单的分析一些Struts的实现机制!
首先,当前台一个请求到达的时候,就会经过Struts的核心过滤器--->
过滤器就可以得到request和response对象-->
根据request得到请求URL(假设是http:8080//localhost/项目名/namespace/methodName)-->
解析该URL字符串,并且得到namespace和methodName-->
根据配置文件struts.xml解析得到对应的类和方法名-->
通过反射来调用对应的方法-->
最后,根据返回的结果,将jsp显示!
当然,上面的分析的确是太简陋,太简单了,实际项目中肯定是复杂得多了(过滤器、拦截器、监听器等等)!上面的分析肯定是基于最简单的情景而分析的。相信在思路上还是讲得通的。因为Struts框架的底层肯定还是Servlet!
好了,今天的博客就写到这里了!不得不感叹,优秀的代码还是要读一些的!因为思路总是相通的!优秀的代码之所有优秀,那是因为优秀的代码集众家之所长!是人类智慧的结晶!
思路分享给大家,希望有所启迪!
浙公网安备 33010602011771号