Servlet

作者: 微笑中的你 | 来源:发表于2018-12-21 16:37 被阅读0次

    Servlet 是运行在服务端的Java小程序,是sun公司提供的接口规范
    用来处理客户端请求,响应给浏览器的动态资源
    servlet的实质就是Java代码,通过java的API动态的向客户端输出内容
    编译成字节码,放到服务器上执行。
    编写程序时,不需要有main函数了。当前发送一个请求的时候,服务器就会按照一定规则调用编写的代码。

    第一个servlet
    public class FirstServlet implements Servlet{
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("------init");
        }
        @Override
        public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
            System.out.println("------service");
            HttpServletResponse httpResponse = (HttpServletResponse)response;
            httpResponse.getWriter().write("aaaaaaaaaaaaaaa");
        }
        @Override
        public void destroy() {
            System.out.println("------destroy");
        }
        @Override
        public ServletConfig getServletConfig() {
            System.out.println("------getServletConfig");
            return null;
        }
        @Override
        public String getServletInfo() {
            System.out.println("------getServletInfo");
            return null;
        }
    }
    
    web.xml文件中配置servlet
      <servlet>
        <servlet-name>myservlet</servlet-name>
        <servlet-class>com.lz.servlet.FirstServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>myservlet</servlet-name>
        <url-pattern>/first</url-pattern>
      </servlet-mapping>
    

    在浏览器中输入效果如图1:


    图1

    原理:在浏览器输入地址回车后。tomcat就会解析该地址,然后就会到web.xml中去匹配该地址,找到servle映射first,然后找到servlet的对应类名称,就会创建对应对象。内部机制是用反射实现的。

    类的加载时机

    当程序要使用某个类时,如果该类还未加载到内存中。系统会通过加载、连接
    初始化三步来实现对这个类进行初始化。

    • 加载
      就是指将class文件读入到内存,并创建一个对象。任何类被使用时,系统都会创建对应的对象。
    • 连接
      验证是否有正确的内部结构,并和其他类协调一致;负责为类的静态成员分配内存,并设置默认值
    • 初始化
      初始化成员变量等

    加载时机:创建类的实例,访问类的静态变量和赋值,调用类的静态方法,初始化某个类的子类,使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。

    类加载器 classLoader

    负责将.class文件加载到内存中,并生成对应的Class对象。
    分类:

    • 根类加载器
      也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在jdk中jre目录下的lib目录下rt.jar文件中
    • 扩展类加载器
      负责jre的扩展目录中的jar包加载,在jdk中jre目录的etx目录
    • 系统类加载器
      负责在jvm启动时加载来自java命令的class文件以及classpath环境变量所指定的jar包和类路径。
    反射

    运行状态下,可以获取任意类的所有属性和方法。
    对于任意对象,都能够调用它的任意一个方法和属性。
    这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    想要使用反射,必须的要获取字节码文件。

    获取字节码文件

    • 方式一 Class类中静态方法forName()
      Class c1 = Class.forName("com.lz.bean.Person");
    • 方式二 动态属性class
      Class c2 = Person.class;
    • 方式三 Object类的getClass()方法
      Person p = new Person();
      Class c3 = p.getClass();

    代码1

            (获取字节码)
            Class c1 = Class.forName("com.lz.reflect.Person");
            通过字节码创建对象
            Person p = (Person) c1.newInstance();
            p.setName("phonegg");
            p.setEmail("phonegg@foxmail.com");
            p.show();
            
            通过有参数的构造器来创建对象
            Constructor c = c1.getConstructor(String.class, String.class);
            Person p2 = (Person) c.newInstance("gjj","gjj@qq.com");
            p2.show();
    
    
    HttpServletRequest
    
    @WebServlet("/request")
    public class RequestServlet extends HttpServlet {
    
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            
            System.out.println("------------获取请求信息------------");
    请求行
            获取请求方式
            String method = request.getMethod();
            System.out.println(method);
            
               获取请求Uri
            String requestUri = request.getRequestURI(); //从项目开始
            System.out.println(requestUri); 
            GET请求   uri  /Servlet/request     
            POST请求  uri  /Servlet/request     
            String requestUrl = request.getRequestURL().toString(); 
            System.out.println(requestUrl);
            GET请求   url  http://localhost:8080/Servlet/request
            POST请求  url  http://localhost:8080/Servlet/request
            
            请求参数
            String queryString = request.getQueryString();
            System.out.println(queryString);
            GET请求   queryString  name=aaa&age=1
            GET请求   queryString  null
            
            当前项目根路径
            String contextPath = request.getContextPath();
            System.out.println(contextPath);
            
    
            System.out.println("----------请求头信息------------");
    请求头
            获取所有请求头名称
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                System.out.println(" name: " + headerNames.nextElement());
            }
            
            System.out.println("----------------------");
    
            获取指定的请求头
            String header = request.getHeader("referer"); //获取访问来源
            System.out.println(" referer: "+header);
            
    //      if (header.equals("http://localhost:8080/Servlet/request.html")) {
    //          response.sendRedirect("/Servlet/request.html");
    //      }
    //      
            System.out.println("----------------------");
            
            获取所有请求头名称和值
            Enumeration<String> headerNamesValues = request.getHeaderNames();
            while (headerNamesValues.hasMoreElements()) {
                String name = headerNamesValues.nextElement();
                String value = request.getHeader(name);
                System.out.println(" name: " + name+ ", value:"+value);
            }
    
              System.out.println("---------请求体-------------");
    请求体
            获取请求参数
            String name = request.getParameter("name");
            int age = Integer.parseInt(request.getParameter("age"));
            String sex = request.getParameter("sex");
            System.out.println("name:"+name+", age:"+age+", sex:"+sex);
            String[] hobby = request.getParameterValues("hobby");
            System.out.println("爱好:"+Arrays.toString(hobby));
            
            System.out.println("----------------------");
    
            获取所有请求参数名称
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                System.out.println(parameterNames.nextElement());
            }
            
            System.out.println("----------------------");
    
            获取所有请求参数键值对
            Map<String, String[]> param = request.getParameterMap();
            for (Map.Entry<String, String[]> entry : param.entrySet()) {
                String key = entry.getKey();
                String[] values = entry.getValue();
                System.out.println("key="+key+", valuse="+Arrays.toString(values));
            }
        }
    }
    

    form表单提交中文乱码

    //发送form请求时,会对请求参数进行编码,格式为ISO8859-1 不支持中文

    • 单个修改 拿到单个参数修改
    String sex = request.getParameter("sex");
    System.out.println(sex);
    byte[] bytes = sex.getBytes("ISO8859-1");
    String sexUtf = new String(bytes, "utf-8");
    System.out.println(sexUtf);
    
    • 统一修改 通过request修改所有,只能用于POST请求
    request.setCharacterEncoding("UTF-8");
    

    HttpServletResponse

    @WebServlet("/response")
    public class ResponseServlet extends HttpServlet {
    
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            默认编码为 ISO 8859-1 并不支持中文
            response.setCharacterEncoding("UTF-8");
            告诉浏览器 使用编码格式
            response.setHeader("Content-Type", "text/html;charset=UTF-8");
            第一要写在最前面,否则可能仍为乱码。
            response.getWriter().write("你真好");
    
            设置响应状态码
            response.setStatus(302);
            
            添加响应头
            response.addHeader("name", "lz");
            response.addIntHeader("age", 20);
            response.addDateHeader("my-date", new Date().getTime());
            
            修改响应头
            response.setHeader("name", "lxf");
            
            请求重定向:
            response.setHeader("location", "/Servlet/login");
            response.sendRedirect("/Servlet/login");
            
            定时重定向  各3秒后重定向
            response.setHeader("refresh", "3;url=/Servlet/login");
    
            请求转发
            RequestDispatcher dispatcher = request.getRequestDispatcher("/s2");
            dispatcher.forward(request, response);
    
        }
    }
    
    

    重定向 和 转发 对比

    • 1 写法不同

      重定向: 重定向是通过response来操作的
      response.setHeader("location", "/Servlet/login");
      response.sendRedirect("/Servlet/login");
      定时重定向 各3秒后重定向
      response.setHeader("refresh", "3;url=/Servlet/login");
      转发: 转发是通过request来操作
      RequestDispatcher dispatcher = request.getRequestDispatcher("/s2");
      dispatcher.forward(request, response);

    • 2 地址栏变化不同

      重定向: 地址栏发生变化
      转发: 地址栏不变

    • 3 访问服务器次数不同

      重定向: 重定向是在客户端完成操作的,浏览器访问了服务器 两次
      转发: 转发是在服务器端完成操作的,浏览器访问了服务器 一次

    • 4 作用范围不同

      重定向: 可以重定向其他网址
      转发: 只能在当前项目进行操作

    ServletContext

    @WebServlet("/context")
    public class ContextServlet extends HttpServlet {
    
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            ServletContext context = getServletContext();
            System.out.println(context);
            获取WebContent下文件
            String aPath = context.getRealPath("a.text");
            System.out.println("a.path--"+aPath);
            
            获取WEB-INF下文件  拼接路径
            String bPath = context.getRealPath("WEB-INF/b.txt");
            System.out.println("bPath----"+bPath);
    
            
            获取src下的文件 先加载该文件
            String cPath = this.getClass().getClassLoader().getResource("c.txt").getPath();
            System.out.println(cPath);
        }
    
    }
    
    servlet中以二进制读取图片
    @WebServlet("/img")
    public class ImgServlet extends HttpServlet {
    
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            
            String path = getServletContext().getRealPath("noti.jpg");
            
            输入流
            FileInputStream in = new FileInputStream(path);
            
            输出流
            ServletOutputStream out = response.getOutputStream();
            
            byte[] b = new byte[1024];
            int len = 0;
            while ((len = in.read(b)) != -1) {
                System.out.println(len);
                System.out.println(Arrays.toString(b));
                out.write(b, 0, len);
            }
    
        }
    }
    
    
    servlet 实现下载
    @WebServlet("/download")
    public class DownLoadServlet extends HttpServlet {
    
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    提取需要下载的文件名
            String filename = request.getParameter("filename");
            System.out.println(filename);
            //默认会对参数进行 ISO8859-1 编码, 中文名称的文件就会乱码
            
    转回为二进制位
            byte[] bname = filename.getBytes("ISO8859-1");
            再使用utf-8进行编码
            filename = new String(bname, "utf-8");
            System.out.println(filename);
            
    设置MIME类型, 即文件类型尾缀
            String mimeType = getServletContext().getMimeType(filename);
            response.setContentType(mimeType);
            
    告诉浏览器以附件打开
            response.setHeader("Content-Disposition", "attachment;"); 
            修改下载是文件名称
            response.setHeader("Content-Disposition", "attachment;filename="+filename); 
    
    根据不同浏览器进行中文编码, 因为不同浏览器默认编码不同
            String agent = request.getHeader("User-Agent");
            String encodedName = "";
            if (agent.contains("MSIE")) {
                如果是IE浏览器
                encodedName = URLEncoder.encode(filename, "utf-8");
                System.out.println(encodedName);
                encodedName = encodedName.replace("+", " ");
                System.out.println(encodedName);
            } else if (agent.contains("Firefox")) {
                如果是火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                encodedName = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
            } else {
                其他浏览器编码
                encodedName = URLEncoder.encode(filename, "utf-8");
            }
            response.setHeader("Content-Disposition", "attachment;filename="+encodedName); 
    
            以流形式读取
            String path = getServletContext().getRealPath(filename);
            FileInputStream in = new FileInputStream(path);
            ServletOutputStream out = response.getOutputStream();
            
            byte[] b = new byte[1024];
            int len = 0;
            while ((len = in.read(b)) != -1) {
                out.write(b, 0, len);
            }
            关闭流是否资源
            in.close();
        
        }
    }
    

    Cookie

            Cookie age = new Cookie("age", "100");      
            
            //设置cookie的保存时间
            age.setMaxAge(60);
            //设置cookie携带路径。。。在我工程路径下都可以携带cookie
    //      age.setPath("/Cookie_Session");
            //默认情况下,url请求头中会携带父级级路径中的cookie和同级路径的cookie
            response.addCookie(age);
            
            //删除cookie的保存时间修改为0即可。
    //      age.setMaxAge(0);
            
            
            //获取指定cookie 比较cookie名字
            Cookie[] cookies = request.getCookies();
            if (cookies!=null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("age")) {
                        System.out.println(cookie.getValue());
                    }
                }           
            }
    

    Session

    session 的创建

    第一次执行request.getSession()时创建。

    session 的销毁
    • 服务器关闭
    • session过期。默认30分钟,最后一次操作计时
    • 手动销毁 session.invalidate();
    • 浏览器关闭,并不一定会销毁该session,为什么访问不到session,是因为依赖JSESSIONID查找session,然而这个ID是存储在Cookie中的,在关闭浏览器后再次访问时就不会携带该ID,会重新创建session。
    
            session 判断是否存在的依据
        通过cookie中携带的JSessionId判断
        
            HttpSession session = request.getSession();
            String name = (String) session.getAttribute("name");
            Integer age = (Integer) session.getAttribute("age");
            
            session.invalidate();
            
            System.out.println("姓名:"+name+", 年龄:"+age);
    

    Cookie Session 对比

    • cookie存储在浏览器端, session存储在服务器端。
    • cookie 生命周期是从创建计时, session 的生命周期是从最后一次操作计时。

    相关文章

      网友评论

          本文标题:Servlet

          本文链接:https://www.haomeiwen.com/subject/lqlrhqtx.html