servlet学习

 推荐一个博客: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("\n");
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 + "\n" + "set usrId = 123");
14         }else{
15             response.getWriter().print("浏览器每次请求携带sesstion,sessionId: " + sessionId
16                     + "\n" + "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提供的对应接口即可

posted @ 2019-08-26 22:12  啊哈啊  阅读(210)  评论(0编辑  收藏  举报