javaWeb——Servlet(一)

前言:
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。

一、什么是servlet?

  • 概念:运行在服务器端的小程序
    Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
    将来我们自定义一个类,实现Servlet接口,复写方法。
    servlet01.png

浏览器请求动态资源找的是java类,但这种java类依赖于服务器才能运行,并且必须要遵守一定的规则(接口)才 能运行。这里的规则就是servlet 即servlet就是一个接口。

参考:javaEE 7 API
servlet02.png

二、快速入门

1. 创建JavaEE项目

servlet3.png
File —>java Enterprise —> 选择合适的JavaEE版本与tomcat的版本 —> 勾选WebApplication —> Next

2. 定义一个类,实现Servlet接口

  1. package com.zxy.web.servlet;
  2. import javax.servlet.*;
  3. import java.io.IOException;
  4. public class ServletDemo1 implements Servlet {
  5. @Override
  6. public void init(ServletConfig servletConfig) throws ServletException {
  7. }
  8. @Override
  9. public ServletConfig getServletConfig() {
  10. return null;
  11. }
  12. //提供服务的方法
  13. @Override
  14. public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
  15. System.out.println("Hello Servlet");
  16. }
  17. @Override
  18. public String getServletInfo() {
  19. return null;
  20. }
  21. @Override
  22. public void destroy() {
  23. }
  24. }

  1. 3. 实现接口中的抽象方法

图片.png

4. 配置Servlet

在web.xml中配置:

  1. <!--配置Servlet -->
  2. <servlet>
  3. <servlet-name>demo1</servlet-name>
  4. <servlet-class>com.zxy.web.servlet.ServletDemo1</servlet-class>
  5. </servlet>
  6. <servlet-mapping>
  7. <servlet-name>demo1</servlet-name>
  8. <url-pattern>/demo1</url-pattern>
  9. </servlet-mapping>
  • 由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用元素和元素完成。
  • 元素用于注册Servlet,它包含有两个主要的子元素:和,分别用于设置Servlet的注册名称和Servlet的完整类名。
  • 一个元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:和,分别用于指定Servlet的注册名称和Servlet的对外访问路径.

    5、执行原理

    Servlet执行原理.png
    流程图说明:
  1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
  2. 查找web.xml文件,是否有对应的标签体内容。
  3. 如果有,则在找到对应的全类名
  4. tomcat会将字节码文件加载进内存,并且创建其对象
  5. 调用其方法

    三、servlet中的生命周期

    简介:

    Servlet生命周期,即阐述Servlet从产生到毁灭的整个过程。
    在Servlet产生到消亡的过程中,有三个生命周期函数,初始化方法init(),处理客户请求的方法service(),终止方法destroy()。

    1. 被创建:执行init方法,只执行一次

  • Servlet什么时候被创建?
    默认情况下,第一次被访问时,Servlet被创建
    可以配置执行Servlet的创建时机。
    标签下配置
    1). 第一次被访问时,创建
    的值为负数
    2). 在服务器启动时,创建
    的值为0或正整数
    Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
    多个用户同时访问时,可能存在线程安全问题。
    解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值

    2. 提供服务:执行service方法,执行多次

  • 每次访问Servlet时,Service方法都会被调用一次。

    3. 被销毁:执行destroy方法,只执行一次

  • Servlet被销毁时执行。服务器关闭时,Servlet被销毁
    只有服务器正常关闭时,才会执行destroy方法。
    destroy方法在Servlet被销毁之前执行,一般用于释放资源

    四、servlet3.0

  • 好处:

支持注解配置。可以不需要web.xml了。

  • 步骤:
  1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
  2. 定义一个类,实现Servlet接口
  3. 复写方法
  4. 在类上使用@WebServlet注解,进行配置
  1. @WebServlet("资源路径")
  2. @Target({ElementType.TYPE})
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Documented
  5. public @interface WebServlet {
  6. String name() default "";//相当于<Servlet-name>
  7. String[] value() default {};//代表urlPatterns()属性配置
  8. String[] urlPatterns() default {};//相当于<url-pattern>
  9. int loadOnStartup() default -1;//相当于<load-on-startup>
  10. WebInitParam[] initParams() default {};
  11. boolean asyncSupported() default false;
  12. String smallIcon() default "";
  13. String largeIcon() default "";
  14. String description() default "";
  15. String displayName() default "";
  16. }

五 HttpServletRequest 与 HttpServletResponse

request是请求对象,携带请求体的所有内容
response是响应对象,返回给客户访问的所有信息

javax.servlet.http Interface HttpServletRequest 是ServletRequest的子类,
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
javax.servlet.http Interface HttpServletResponse 是ServletResponse的子类
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html

登录效验 and 返回json或xml的使用

  1. package com.lijunyang.filter;
  2. import com.lijunyang.util.JedisPoolUtils;
  3. import javax.servlet.*;
  4. import javax.servlet.http.HttpServletRequest;
  5. import java.io.IOException;
  6. import java.io.OutputStream;
  7. import java.util.ArrayList;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import java.util.regex.Pattern;
  11. public class loginFilter implements Filter {
  12. private List accessList = new ArrayList<>();
  13. public void destroy() {
  14. }
  15. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  16. HttpServletRequest request = ((HttpServletRequest) req);
  17. String url = request.getRequestURI();
  18. Boolean flag = false;
  19. for (Iterator<String> list = accessList.iterator(); list.hasNext();){
  20. StringBuffer str = new StringBuffer(list.next());
  21. str.append("/*");
  22. Boolean bool = Pattern.matches(str.toString(), url);
  23. if (bool) {
  24. // 需要校验的
  25. String uuid = request.getHeader("JSESSIONID");
  26. String jSessionId = JedisPoolUtils.getJsessionId(uuid);
  27. if (jSessionId != "") { // 具备登录状态的
  28. flag = true;
  29. break;
  30. } else { // 无登录状态
  31. flag = false;
  32. break;
  33. }
  34. } else {
  35. // 不需要效验的
  36. flag = true;
  37. }
  38. }
  39. if (flag) {
  40. chain.doFilter(req, resp);
  41. } else {
  42. // resp.setStatus(400) 这个可以修改http响应状态,常用
  43. if (true) {
  44. resp.setContentType("application/json; charset=utf-8");
  45. resp.setCharacterEncoding("UTF-8");
  46. OutputStream out = resp.getOutputStream();
  47. out.write(("{\"message\":\"无登录状态\",\"error\":\"\",\"data\":\"\",\"code\":\"10001\"}").getBytes("UTF-8"));
  48. out.flush();
  49. out.close();
  50. } else {
  51. resp.setContentType("text/xml;charset=UTF-8");
  52. resp.setCharacterEncoding("UTF-8");
  53. PrintWriter out = resp.getWriter();
  54. StringBuilder builder = new StringBuilder();
  55. builder.append("<result>")
  56. builder.append("<message>");
  57. builder.append("无登录状态");
  58. builder.append("</message>");
  59. builder.append("<error>");
  60. builder.append("");
  61. builder.append("</error>");
  62. builder.append("<code>");
  63. builder.append("10001");
  64. builder.append("</code>");
  65. builder.append("<data>");
  66. builder.append("10001");
  67. builder.append("</data>");
  68. builder.append("</result>")
  69. out.println(builder.toString());
  70. out.flush();
  71. out.close();
  72. }
  73. }
  74. }
  75. public void init(FilterConfig config) throws ServletException {
  76. accessList.add("/fileupload/upload"); // 上传图片
  77. accessList.add("/goodsInsertOne"); // 新建商品
  78. accessList.add("/enum_add"); // 新建枚举
  79. }
  80. }

六 案例

  1. // String path = request.getContextPath();
  2. // String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  3. // System.out.println("basePath:"+basePath);
  4. // System.out.println("getContextPath:"+request.getContextPath());
  5. // System.out.println("getServletPath:"+request.getServletPath());
  6. // System.out.println("getRequestURI:"+request.getRequestURI());
  7. // System.out.println("getRealPath:"+request.getRealPath("/"));
  8. // System.out.println("getServletContext().getRealPath:" + getServletContext().getRealPath("/")); // getServletContext 可能不存在,依赖问题
  9. // System.out.println("getQueryString:"+request.getQueryString());
  10. /*
  11. basePath:http://localhost:8080/test/
  12. getContextPath:/test
  13. getServletPath:/test.jsp
  14. getRequestURI: /test/test.jsp HttpServletRequest
  15. getRequestURL: http://localhost:8080/test/test.jsp ServletRequest
  16. getRealPath:D:\Tomcat 6.0\webapps\test\
  17. getServletContext().getRealPath:D:\Tomcat 6.0\webapps\test\
  18. getQueryString:p=fuck
  19. **/

设置跨域 CORS(跨域资源共享)

  1. package com.lijunyang.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. import java.io.IOException;
  6. import java.util.Arrays;
  7. import java.util.Enumeration;
  8. import java.util.HashSet;
  9. import java.util.Set;
  10. public class accessControlAllowOriginFilter implements Filter {
  11. public void destroy() {
  12. }
  13. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
  14. // 将ServletResponse转换为HttpServletResponse
  15. HttpServletResponse httpResponse = (HttpServletResponse) res;
  16. // 如果不是80端口,需要将端口加上,如果是集群,则用Nginx的地址,同理不是80端口要加上端口
  17. String [] allowDomain= { "http://localhost:3000" };
  18. Set allowedOrigins= new HashSet(Arrays.asList(allowDomain));
  19. HttpServletRequest request = ((HttpServletRequest) req);
  20. Enumeration er = request.getHeaderNames();//获取请求头的所有name值
  21. while(er.hasMoreElements()){
  22. String name =(String) er.nextElement();
  23. String value = request.getHeader(name);
  24. // System.out.println(name+"="+value);
  25. }
  26. String originHeader=((HttpServletRequest) req).getHeader("Origin");
  27. if (allowedOrigins.contains(originHeader)){
  28. httpResponse.setHeader("Access-Control-Allow-Origin", originHeader);
  29. // httpResponse.setContentType("application/json;charset=UTF-8");
  30. httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
  31. httpResponse.setHeader("Access-Control-Max-Age", "3600");
  32. httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
  33. // 如果要把Cookie发到服务器,需要指定Access-Control-Allow-Credentials字段为true
  34. httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
  35. httpResponse.setHeader("Access-Control-Expose-Headers", "*");
  36. }
  37. chain.doFilter(req, res);
  38. }
  39. public void init(FilterConfig config) throws ServletException {
  40. }
  41. }