推荐一个博客:https://www.cnblogs.com/xdp-gacl/tag/JavaWeb学习总结/default.html?page=3
这里有将tomcat和serlvet的知识,很详细,有示例
一、使用idea搭建Servlet程序
https://blog.csdn.net/jesonjoke/article/details/78276714
问题解决:
1 tomcat和servlet、java有版本兼容性问题
警告 [RMI TCP Connection(2)-127.0.0.1] org.apache.tomcat.util.descriptor.web.WebXml.setVersion Unknown version string [4.0]. Default version will be used.
原因:低版本的tomcat不兼容高版本的servlet和java,参照官网http://tomcat.apache.org/whichversion.html,换成tomcat高版本即可
2 idea tomcat 控制台乱码
使用了网上的多种改变编码的方法,还是不行,最后发现tomcat9的日志输出格式就是utf-8。我猜应该是中文操作系统idea的控制台是GBK编码,修改方法如下:
1、找到${CATALINA_HOME}/conf/logging.properties
2、找到java.util.logging.ConsoleHandler.encoding = UTF-8
修改为java.util.logging.ConsoleHandler.encoding = GBK
二、Servlet线程安全性问题
https://yq.aliyun.com/articles/612905
Servlet是单例多线程,一个请求对应一个线程,每个线程去调用service方法,要保证安全性问题,尽量避免在doGet等方法中使用servlet类实例的变量,而使用在doGet等方法中使用局部变量,这样多线程就不会出现线程安全问题(每个线程有自己的虚拟机栈用于存储局部变量)。如果实在要使用实例变量,使用synchronized进行同步(效率比较低,因为会有较多线程同步,阻塞严重)。当然远古可以设置servlet为多例单线程,实现SingleThreadModel接口即可,容器会创建对各请求创建一个实例,这将引起大量的系统开销,SingleThreadModel在Servlet2.4中已被不提倡。
三、简单的Servlet程序(纯后台Serlvet,返回json数据)
可以使用postman发送get请求报文,数据放在body中。在servlet中使用inputStream进行获取body中的内容,将其读出即可。
1 @WebServlet("/ServletReJSON") 2 public class ServletReJSON extends HttpServlet { 3 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 } 6 7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 8 InputStream is = request.getInputStream(); 9 int byteLength = request.getContentLength(); 10 byte b[] = new byte[byteLength]; 11 int len = is.read(b); 12 StringBuilder repJson = new StringBuilder("{msgJson:"); 13 repJson.append(new String(b)).append("}"); 14 response.setContentType("text/javascript"); 15 response.getWriter().print(repJson.toString()); 16 } 17 }
四、servlet过滤器:filter
在请求传到servlet处理之前和servlet传出响应到客户端之前,进行一次过滤操作
过滤器实现javax.servlet.Filter类,实现doFilter方法即可。写好filter类之后,在web.xml中配置好filter的过滤地址(即哪些地址需要被过滤)
filter类:
1 public class MyTestFilter implements Filter { 2 public void destroy() { 3 } 4 5 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { 6 System.out.println("doFilter! --request"); //过滤请求的代码写在这里 7 chain.doFilter(req, resp); //一旦执行doFilter,过滤器就会把请求交给下一个过滤器,如果没有下一个过滤器,那就传给匹配的servlet 8 System.out.println("doFilter! --response"); //根据过滤器链依次传递响应到每一个过滤器 9 } 10 11 public void init(FilterConfig config) throws ServletException { 12 String param = config.getInitParameter("MyParam"); //获取在web.xml中配置的过滤器的filterConfig参数 13 System.out.println("myFilter init!"); 14 System.out.println(param+"!"); 15 } 16 }
web.xml配置:
1 <filter> 2 <filter-name>MyTestFilter</filter-name> 3 <filter-class>com.lzj.filter.MyTestFilter</filter-class> 4 <init-param> 5 <param-name>MyParam</param-name> 6 <param-value>get my param</param-value> 7 </init-param> 8 </filter> 9 <filter-mapping> 10 <filter-name>MyTestFilter</filter-name> 11 <url-pattern>/TestFilterServlet</url-pattern> 12 </filter-mapping>
五、session/cookie
http协议是无状态协议,当一个用户想要登陆一次就能持续获取后台数据,后台程序就要使用cookie和session来保持这个连接
cookie
浏览器发送请求到servlet后台程序时,servlet创建一个cookie对象,然后返回响应,浏览器根据响应的cookie信息,在本地创建一个cookie文件。以后每次发送请求就带上这个cookie
可以为cookie设置key-value值,cookie有多对key-value值,servlet中可以通过request获取,也可以通过response设置
使用postman发送请求,可以看到这里返回了json内容,如果请求没有发送cookie就会提示无cookie或者已过期
1 @WebServlet("/CookieServlet") 2 public class CookieServlet extends HttpServlet { 3 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 } 6 7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 8 Cookie[] reqCookies = request.getCookies(); 9 Cookie cookieName = new Cookie("name", "heh"); 10 Cookie cookieSex = new Cookie("sex", "nan"); 11 cookieName.setMaxAge(60*2); 12 response.addCookie(cookieName); 13 response.addCookie(cookieSex); 14 StringBuilder resp = new StringBuilder(""); 15 if(reqCookies != null){ 16 for (Cookie reqCookie : reqCookies) { 17 resp.append(reqCookie.getName()).append(":").append(reqCookie.getValue()).append(" "); 18 } 19 }else{ 20 resp.append("无cookie或者已过期"); 21 } 22 response.setContentType("text/javascript;charset=utf-8"); 23 response.getWriter().print(resp.toString()); 24 } 25 }
session
session也是为了保持浏览器和服务器之间状态。其利用了cookie来承载一个sessionid,cookie的key值为JSESSIONID,value值为sessionid的值,对应到服务器后台,sessionid对应了一个session对象,这个对象可以放很多key-value值,可以理解为cookie的升级(因为cookie的大小是有限的)
session集合在后台被Manager的一个类保存,每次请求时,容器会根据前台请求cookie中的的sessionid(或者url中的sessionid,这是为了避免有些浏览器不支持cookie)在session集合中找到对应的session对象,赋值到容器request对象中。在request对象中可以通过request.getSession()来获取这个session对象,如果没有获取到session对象则创建一个新的session对象(同时添加这个session到session集合中,并设置response header的cookie值)
1 @WebServlet("/SessionServlet") 2 public class SessionServlet extends HttpServlet { 3 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 } 6 7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 8 HttpSession session = request.getSession(); // 获取session,如果request没有session就创建一个新session,并且添加到sesssion集合并设置response header的cookie值 9 String sessionId = session.getId(); 10 response.setContentType("text/javascript;charset=utf-8"); 11 if(session.isNew()){ 12 session.setAttribute("usrId", "123"); 13 response.getWriter().print("服务端第一次新建sesstion,sessionId: " + sessionId + " " + "set usrId = 123"); 14 }else{ 15 response.getWriter().print("浏览器每次请求携带sesstion,sessionId: " + sessionId 16 + " " + "getUsrId:" + session.getAttribute("usrId")); 17 } 18 } 19 }
六、乱码问题
七、servlet监听器:listenner
servlet监听器是Servlet规范中定义的一种特殊类,它用于监听web应用程序中的ServletContext, HttpSession和 ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
以如何写一个ServletContextListener监听器为例:
ServletContextListener负责监听servletContext对象的创建和销毁(context对应一个web应用,可参考tomcat结构,可以说servletContext对象就是一个web应用的全局对象)
1. 首先创建一个监听的servletContext的类,实现serlvet的ServletContextListener接口,实现其两个方法
1 import javax.servlet.ServletContextEvent; 2 import javax.servlet.ServletContextListener; 3 4 public class MyServletContextListener implements ServletContextListener { 5 6 @Override 7 public void contextInitialized(ServletContextEvent sce) { 8 System.out.println("ServletContext对象创建"); 9 } 10 11 @Override 12 public void contextDestroyed(ServletContextEvent sce) { 13 System.out.println("ServletContext对象销毁"); 14 } 15 }
2. 在web.xml配置监听器
<listener> <description>ServletContextListener监听器</description> <listener-class>com.lzj.listener.MyServletContextListener</listener-class> </listener>
其他监听同理,实现serlvet提供的对应接口即可