Servlet

JavaWeb

概念 : 就是使用Java技术开发web页面

资源分类 :

         静态资源: 所有用户看到内容都一样,静态的页 面,html、css、js..

         动态资源: 用户看到内容可能不一样的, jsp/servlet、php、asp...

web应用程序

        概念:提供给浏览器访问的程序,将来写完JavaWeb项 目之后,需要将项目部署到web应用程序中,提供给外界访 问

         web项目包含的内容:

                 静态的页面、配置文件(properties..)、Java文件、 jar包

        web服务器 :

                 服务器表示安装了服务器软件的计算机

                服务器软件指的是可以接受用户请求,处理请求, 做出响应,比如安装了mysql,用户可以登录mysql,可以发出查询指令,服务器可以将登录、查询指令返回 给用户

        web服务器指的是,可以部署web项目,可以让用 户通过浏览器来访问

        常用的web服务器:

                1,webLogic :oracle公司,支持所有的 JavaEE的规范,收费

                2,webSphere :IBM公司,支持所有的 JavaEE的规范,收费

                3,JBOSS:JBoss,支持所有的JavaEE的规 范,收费

                4,Tomcat:apache基金会的项目,支持 Servlet\jsp规范,免费

Tomcat的使用

下载:https://tomcat.apache.org/

安装:直接将压缩包解压缩

启动、配置

启动文件、关闭文件

双击启动,有如下内容表示启动成功

通过浏览器访问http://localhost:8080/

启动的问题:

        1,启动闪退, Java运行环境问题

        2,启动报错,8080端口被占用,

                1,找到占用的程序,去结束掉占用进程 使用命名: netstat -ano

                 2,修改tomcat启动的端口号 找到conf目录下的server.xml ,修改其端 口号

        3,乱码问题

        找到conf目录下的

将配置代码内容改为GBK

面试题 :

        网站是怎么进行访问的?

        1,输入网站域名,回车访问

        2,域名会先到本地 C:\Windows\System32\drivers\etc 下的hosts文件中,检 查是否存在域名映射

         3,如果存在域名映射,则将此域名映射的ip地址返回

         4,如果不存在,则去域名解析器中,匹配对应的服务 器ip地址,如果有地址,则访问成功

tomcat中部署web网站的方式

三种部署方式:

        1,将项目文件,部署到tomcat下的webapps目录中

                新建一个hello目录,里面放入一个hello.html文 件,然后将这个目录,复制到webapps目录下

                在tomcat的后面直接访问 /hello/hello.html 就能 访问到对应的html页面了

2,通过配置文件部署项目(使用的较少,需要修改配置 文件)

        在server.xml文件中,找到<hosts> 标签,在标签 中配置<Context>标签

        两个属性 : docBase 表示项目的位置 path 表示浏览器中访问的虚拟路径

配置完之后的访问地址

3,动态部署的方式

        找到conf/catalina/localhost目录,在目录中创建 任意名称的 xml文件

编写文件内容,<Context bocBase="D:\hello"/>

第三种方式,是一种热部署的方式,将来工具中比 较常用

idea中集成Tomcat

创建项目

目录构造

编写html文件

启动tomcat,在浏览器中访问hello.html

修改虚拟路径,完成指定html文件的访问

修改端口号,完成指定的html文件的访问

单独再添加一个tomcat服务器,完成访问

idea中怎么部署项目?

通过查看idea启动后,后台的地址

在这个地址后,和之前tomcat目录下的conf目录差不多, 翻到最后,localhost目录下,有一个xml文件

这个xml文件,其实就是idea帮助我们动态部署的那个文件 这个文件中,指向一个地址,这个地址就是idea中,项目运 行的真正位置

 指向项目中的out目录下(或者target目录下)的位置

Servlet学习

servlet概念

        概念 : 由server applet 两个单词缩写,翻译过来就 是: 运行在服务器端的小程序

        Servlet的作用 :

                浏览器可以通过域名和端口,找到我们的服务器, 找到的是服务器上的tomcat

                服务器上的项目资源分为静态资源和动态资源,服 务器可以直接将静态资源返回给浏览器,浏览器可以解 析,动态资源不能直接返回给浏览器,浏览器无法识 别,只能通过servlet处理之后,返回给浏览器

                所以,servlet的作用,主要就是接受浏览器发送到 服务器的请求,把请求处理后,再将结果返回给浏览 器,浏览器在发送数据的时候,需要按照指定的规则去 完成发送,满足servlet要求后,才能获取到浏览器的数 据。

                在Java中,定义指定的规则内容的都是接口, Servlet其实就是一个接口,这个接口定义了java类被浏 览器访问的规则。

Servlet实现

        1,编写一个类,实现Servlet接口

        2,实现所有Servlet接口的方法

        3,在init方法、service方法、destroy方法中编写代码

        4,service方法是Servlet中的核心方法,将来浏览器的 请求和响应都会在这个方法中进行处理

public class ServletDemo implements Servlet {


    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("servlet初始化--");
    }

    //配置
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }


    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //通过ServletRequest对象请求数据
        String username = servletRequest.getParameter("username");
        System.out.println(username);

        System.out.println("service是核心方法,将来的业务逻辑都写在这个方法中");
        System.out.println("只要service被访问,默认就会执行service中的代码");

        //响应的操作
        servletResponse.getWriter().write("hello,response working");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("servlet运行结束之后,对象被销毁了,会调用这个方法");
    }
}

配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置servlet访问-->
    <servlet>
        <servlet-name>demo</servlet-name>
        <servlet-class>com.javaweb.servlet.ServletDemo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>demo</servlet-name>
        <url-pattern>/demo</url-pattern>
    </servlet-mapping>
</web-app>

 

浏览器访问

http://localhost:8088/haha/demo?username=jack

/haha 虚拟路径

/demo web.xml中编写的资源路径

?username=jack 表示携带的请求参数

Servlet运行流程

Servlet的生命周期

        servlet的方法,待不了它的生命周期

常用的方法一般init方法、service方法、destroy方法

1,init方法:

        默认当资源第一次被访问的时候,也就是servlet对象被创建后,执行此方法,执行一次

可以修改执行时间,改为服务器启动之后启动

        在web.xml文件中,servlet标签下,加上一对标签

        <load-on-startup>1</load-on-startup>

        改为0或者其他正整数,表示tomcat服务器启动后就创建

        init方法执行一次,说明在内存中,只存在一个servlet对象,servlet是单例对象

        tomcat本身是支持多线程的,多个用户访问的时候,可能会出现线程安全问题

        将来在使用的时候,尽量不用synchronized牢保证线程安全,因为,一个用户获取锁之后,其他用户都要等待。

        怎么解决?

                尽量不要在Servlet类中定义成员变量,可 以在service方法中定义局部变量,这样每次访问的时候, 局部变量不是所有线程共享的,就不会存在安全问题。

2,service方法

       将来用来提供逻辑服务的方法,每次访问servlet, 都会执行此方法

3,destroy方法

        servlet被销毁时,执行,服务器关闭的时候, servlet对象被销毁,可以用来释放资源等

     Servlet体系结构   

        Servlet接口

                |

        GenericServlet抽象类

                |

        HttpServlet抽象类

        1,Servelt接口是Servlet体系的总接口,每次实现,都 需要实现其5个方法,比较麻烦

        2,GenericServlet是Servelt接口的一个实现类,这个 类里面针对除了service以外的其他方法都做了默认实现, 继承GenericServlet这个类,只要重写service方法就可以 了

        3,但是将来请求发过来,仍然要去判断请求过来使用 的是什么方法,get或者post或者其他方法,所以每次重写 GenericServlet这个类的service方法,还要判断请求的方 法是什么,也比较麻烦

        4,HttpServlet是Servlet接口在遵循Http标准的情况 下,编写的一个子类,它的service方法完成了对各种方法的判断和封装,使用的时候,只需要继承HttpServlet这个 类,然后重写doget和dopost方法即可

public class ServletDemo3 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       // super.doGet(req, resp);
        System.out.println("不管是get还是post请求,都是这个方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doPost(req, resp);
        this.doGet(req,resp);
        //System.out.println("这个方法是将来post方法请求,访问的方法");
    }
}

        

<form action="/servlet/demo3" method="get">
    <input type="submit" value="提交">
</form>
使用servlet完成简单的登录验证
 <!-- 配置servlet-->
    <servlet>
        <servlet-name>ServletDemo1</servlet-name>
        <servlet-class>com.javaweb.servlet1.ServletDemo1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletDemo1</servlet-name>
        <url-pattern>/ServletDemo1</url-pattern>
    </servlet-mapping>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
<form action="/servlet/ServletDemo1" method="get">
    用户名:<input type="text" name="username"> <br>
    密  码:<input type="password" name="password"> <br>
    <input type="submit" value="登录">
</form>
</body>
</html>
public class ServletDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //浏览器请求登录,携带了用户名和密码两个参数,在Servlet中获取用户名和密码
        //通过请求对象HTTPServletRequest,去获取到参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println(username+"--"+password);

        //jdbc的连接


        //判断用户名和密码
        if ("jack".equals(username) && "123456".equals(password)){
            //用户名和密码都正确,就响应登录成功
            response.getWriter().write("login success!");
        }else {
            response.getWriter().write("login lose!");
        }

    }
}

Servlet3.0 使用注解开发

        Servlet3.0之后,在类上加上@WebServlet 就可以完成

        Servlet配置,不用在web.xml中再去配置信息

//@WebServlet("/servletDemo3")
@WebServlet({"/servletDemo3","/s1/*","/s2"})
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //浏览器直接访问是get方法
        System.out.println("Servlet被访问");
    }
}

写法 :   

         一个地址 :@WebServlet("/servletDemo02")

        多个地址:

                @WebServlet({"/servletDemo02","/s1","/s2"})

        地址中有多层结构 :

                @WebServlet({"/servletDemo02","/s1/*","/s2/hello"})

HTTP

        概念:Hypertext Transfer Protocol 超文本传输协议

        传输协议:定义了,客户端和服务端通信的时候,要遵循的 一个协议规定,主要是定义了数据发送和接收的格式

        特点 : 基于TCP/IP协议的高级协议,默认端口80,基于请 求/响应模型的,一次请求对应一次响应,每次请求之间是 相互独立的 Https: 基于http做了一层更加安全的验证 Https端口号是 :443 http版本: 1.0 版本 :每次请求都会重新建立连接 1.1 版本:后续的请求会复用之前请求的连接

Http请求和Htpp响应

        只要将来在浏览器中,输入一个资源路径,去访问资源,就 可以称为是一次请求,每次请求都会伴随着一次响应

Http请求

        Http请求,是从客户端发送出来,发给服务器端的

        http中,请求消息的数据格式:

                1,请求行

     

   请求方法:

        get :表单数据携带在URL地址上、数据不安全、大小没有限制、速度快

        post:表单数据携带在请求体上、数据安全、大小没限制,速度慢

2,请求头

                       组成: 请求头名:请求头

   

        Referer 表示当前请求从那个地址过来      http://localhost:8080/servlet/login.html

        统计工作,防盗链

        user-Agent  显示浏览器的信息       

        Accept:支持解析文件的格式      

        cookie 

                3,请求空行

                        就是一个空行,起到分割作用

                4,请求体(post方法才有请求体,get方法没有)

                        组成:post请求携带的表单数据 

HttpServletRequest对象

ServletRequest(父接口) :

        定义将客户端请求信息提供给某个 servlet 的对象。 servlet 容器创建 ServletRequest 对象,并将该对象作为参 数传递给该 servlet 的 service 方法

                                 |

HttpServletRequest(子接口):

        扩展 ServletRequest 接口,为 HTTP servlet 提供请求信 息。

        servlet 容器创建 HttpServletRequest 对象,并将该对象 作为参数传递给 servlet 的 service 方法(doGet、 doPost,等等)。

                                 |

RequestFacade(实现类)

        通过后台输出doGet方法中提供的request对象,发现 输出的值是

         org.apache.catalina.connector.RequestFacade@48 4653ea

         说明,在使用doGet方法或者doPost方法参数的 request对象或者response对象的方法,实际上使用的是 RequestFacade这个实现类中的方法

HttpServletRequst对象的常用方法

1,获取请求中的各种数据

        获取请求行数据

        String getMethod()返回用于发出此请求的 HTTP 方法的名称,例如 GET、POST 或 PUT

        String getContextPath() 返回请求 URI 指示请求 上下文的那一部分

        String getServletPath() 返回此请求调用 servlet 的 URL 部分

        String getQueryString() 返回包含在请求 URL 中路径后面的查询字符串

        String getRequestURI()返回此请求的 URL 的一 部分,从协议名称一直到 HTTP 请求的第一行中的查询字符串

        StringBuffer getRequestURL() 重新构造客 户端用于发出请求的 URL。返回的 URL 包含一个 协议、服务器名称、端口号、服务器路径,但是不 包含查询字符串参数。

        String getProtocol() 返回请求使用的协议的 名称和版本

        String getRemoteAddr() 返回发送请求的客户端 或最后一个代理的 Internet Protocol (IP) 地址

  //请求行数据的方法
        //String getMethod()返回用于发出此请求的 HTTP 方法的名称,例如 GET、POST 或 PUT
        String method = request.getMethod();
        System.out.println(method);

        //String getContextPath() 返回请求 URI 指示请求 上下文的那一部分
        String contextPath = request.getContextPath();
        System.out.println(contextPath);

        //String getServletPath() 返回此请求调用 servlet 的 URL 部分
        String servletPath = request.getServletPath();
        System.out.println(servletPath);

        //String getQueryString() 返回包含在请求 URL 中路径后面的查询字符串
        String queryString = request.getQueryString();
        System.out.println(queryString);

        //String getRequestURI()返回此请求的 URL 的一 部分,从协议名称一直到 HTTP 请求的第一行中的查询字符串
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);

        //StringBuffer getRequestURL() 重新构造客 户端用于发出请求的 URL。返回的 URL 包含一个 协议、服务器名称、端口号、服务器路径,但是不 包含查询字符串参数。
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);

        //String getProtocol() 返回请求使用的协议的 名称和版本
        String protocol = request.getProtocol();
        System.out.println(protocol);

        //String getRemoteAddr() 返回发送请求的客户端 或最后一个代理的 Internet Protocol (IP) 地址
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);

        获取请求头数据

        String getHeader(String name) 以 String 的 形式返回指定请求头的值。如果该请求不包含指定 名称的头,则此方法返回 null

        Enumeration<E> getHeaderNames() 返回此 请求包含的所有头名称的枚举

@WebServlet("/ServletDemo4")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      
        //获取请求头数据
        String referer = request.getHeader("Referer");
        System.out.println(referer);
        //获取所有请求头的名称
        Enumeration<String> headerNames = request.getHeaderNames();
        //System.out.println(headerNames);

        //遍历
        while (headerNames.hasMoreElements()){
            //遍历每一个headName
            String headName = headerNames.nextElement();
            //通过headName获取每一个值
            String header = request.getHeader(headName);
            System.out.println(headName + "----" + header);
        }


    }
}

        获取请求体数据

        先通过请求对象获取到输入流,再从输入流中拿到 数据

         ServletInputStream getInputStream() 使用

        ServletInputStream 以二进制数据形式获取请求 正文

        BufferedReader getReader() 使用 BufferedReader 以字符数据形式获取请求正文。读取 器根据正文上使用的字符编码转换字符数据

//获取post请求中的表单数据
 //ServletInputStream inputStream = request.getInputStream();
 BufferedReader reader = request.getReader();
 String line = null;
 while ( (line = reader.readLine()) != null){
 System.out.println(line);
 }
HttpServletRequest请求对象的其他功能

        1、获取请求参数的通用方法

        2、请求转发         

        3、共享数据    

        4、获取ServletContext 

1、获取请求参数的通用方法

       String getParameter(String name) 以 String 形 式返回请求参数的值,如果该参数不存在,则返回 null

        Map getParameterMap() 返回此请求的参数的 Map

        Enumeration getParameterNames() 返回包含此请 求中所包含参数的名称的 String 对象的 Enumeration。

        String[] getParameterValues(String name) 返回 包含给定请求参数拥有的所有值的 String 对象数组,如果 该参数不存在,则返回 null。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
<form action="/servlet/ServletLogin" method="get">
    用户名:<input type="text" name="username"> <br>
    密  码:<input type="password" name="password"> <br>
    性  别:<input type="radio" name="gender" value="男"> 男
           <input type="radio" name="gender" value="女">女 <br>
    爱  好:<input type="checkbox" name="hobby" value="game"> 游戏
          <input type="checkbox" name="hobby" value="study"> 学习
          <input type="checkbox" name="hobby" value="ball"> 打球<br>
    籍  贯:
          <select name="home">
              <option name="city" value="nj">南京</option>
              <option name="city" value="sq" >商丘</option>
              <option name="city" value="bj">北京</option>
          </select>


    <input type="submit" value="注册">
</form>
</body>
</html>
@WebServlet("/ServletLogin")
public class ServletLogin extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //获取前台所有参数
        //指定参数名获取时候,只能拿到一个值,拿不全
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String gender = request.getParameter("gender");
        String hobby = request.getParameter("hobby");
        String home = request.getParameter("home");
        System.out.println(username);
        System.out.println(password);
        System.out.println(gender);
        System.out.println(hobby);
        System.out.println(home);

        //
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            //获取参数的键,也就是参数名
            System.out.println("参数名:" + entry.getKey() );
            String[] value = entry.getValue();
            for (String s : value) {
                System.out.println("参数值:"+s);
            }
        }


    }
}
@WebServlet("/ServletLogin")
public class ServletLogin extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,post请求可能存在乱码
        request.setCharacterEncoding("utf8");
        

        //Enumeration getParameterNames() 返回包含此请 求中所包含参数的名称的 String 对象的 Enumeration。
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            System.out.println("参数名: " + paramName);
            for (String paramValue : paramValues) {
                System.out.println("参数值: " + paramValue);
            }
        }

    }
}
@WebServlet("/ServletLogin")
public class ServletLogin extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,post请求可能存在乱码
        request.setCharacterEncoding("utf8");
       

        //String[] getParameterValues(String name) 返回 包含给定请求参数拥有的所有值的 String 对象数组,如果 该参数不存在,则返回 null。
        String[] usernames = request.getParameterValues("username");
        if (usernames != null) {
            for (String username1 : usernames) {
                System.out.println("username: " + username1);
            }
        }
        String[] passwords = request.getParameterValues("password");
        if (passwords != null) {
            for (String password1 : passwords) {
                System.out.println("password: " + password1);
            }
        }

        String[] genders = request.getParameterValues("gender");
        if (genders != null) {
            for (String gender1 : genders) {
                System.out.println("gender: " + gender1);
            }
        }

        String[] hobbies = request.getParameterValues("hobby");
        if (hobbies != null) {
            for (String hobby1 : hobbies) {
                System.out.println("hobby: " + hobby1);
            }
        }

        String[] homes = request.getParameterValues("home");
        if (homes != null) {
            for (String home1 : homes) {
                System.out.println("home: " + home1);
            }
        }

    }
}
 请求乱码问题

        get请求,从tomcat8之后,不存在乱码

        post请求,存在乱码问题

        使用如下方法解决 :

                public void setCharacterEncoding(String env) 重写此请 求正文中使用的字符编码的名称

2、请求转发

        RequestDispatcher getRequestDispatcher(String path) 返回一个 RequestDispatcher 对象,它充 当位于给定路径上的资源的包装器。

        RequestDispatcher 定义接收来自客户端的请求并将 它们发送到服务器上的任何资源 f        orward(ServletRequest request, ServletResponse response) 将请求从一个 servlet 转发到服务器上的另 一个资源(servlet、JSP 文件或 HTML 文件)。

@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("ServletA被请求了,但是没有请求的内容返回,将请求转发给B");

        //第一种写法
        //完成转发操作,先获取RequestDispatcher对象,如何调用forward进行转发
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servletB");
        requestDispatcher.forward(request,response);
        
        //第二种写法
        request.getRequestDispatcher("/servletB").forward(request,response);

    }
}

@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("ServletB拿到了转发给来的请求!");



    }
}

        特点:

                转发是一次请求,转发后,浏览器地址是没有改变,只能转发在服务器内部的资源中。

3、共享数据

        共享数据:指的是一次请求的数据,可以在多个资源中 共享使用

        共享数据,一般要通过域对象来完成数据的共享

        request对象,本身就是一个域对象,可以共享一次请 求范围内的数据,一般在转发的时候会使用共享数据的功能

        使用方法 :

                void setAttribute(String name, Object o) 存储 此请求中的属性。在请求之间重置属性                 Object getAttribute(String name) 以 Object 形式返回指定属性的值,如果不存在给定名称的属性, 则返回 null


@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("ServletA被请求了,但是没有请求的内容返回,将请求转发给B");

        //第一种写法
        //完成转发操作,先获取RequestDispatcher对象,如何调用forward进行转发
//        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servletB");   //因为在本地,所以不需要加虚拟路径
//        requestDispatcher.forward(request,response);
        String username = request.getParameter("username");
        System.out.println(username);

        String name = "jack";

        //调用set方法完成数据的共享
        request.setAttribute("name",name);

        //第二种写法
        request.getRequestDispatcher("/servletB").forward(request,response);

    }
}


@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("ServletB拿到了转发给来的请求!");

        String username = request.getParameter("username");
        System.out.println(username);

        //拿取request域的共享数据
        String name = (String) request.getAttribute("name");
        System.out.println(name);


    }
}

 练习:在登录页输入登录用户名和密码, 提交到LoginServlet,判断,如果用户名是jack,密码是 123456,则将请求转发到SuccessServlet,并且在控制台 输出,登录成功,xxx,欢迎你,如果用户名或者密码不 对,则将请求转发到FailServlet,并在控制台输出:xxx用 户名登录失败,请检查信息

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/servlet/loginServlet" method="post">
    用户名:<input type="text" name="username"> <br>
    密  码:<input type="password" name="password"> <br>
    <input type="submit" value="登录">
</form>
</body>
</html>
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //设置一个共享值
        request.setAttribute("name",username);
        if ("jack".equals(username) && "123456".equals(password)){
            request.getRequestDispatcher("/successServlet").forward(request,response);
        }else {
            request.getRequestDispatcher("/failServlet").forward(request, response);

        }
    }
}
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("utf8");
        String name = (String) request.getAttribute("name");
        System.out.println("登录成功,欢迎你" + name);
        response.getWriter().write("登录成功,欢迎你" + name);

    }
}
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("utf8");
        String name = (String) request.getAttribute("name");
        System.out.println("登录失败,用户名" + name + "有问题!");
        response.getWriter().write("登录失败,用户名" + name + "有问题!");

    }
}
4、获取ServletContext 
Http中的响应

Http响应的组成:

        1、响应行:HTTP/1.1 200 由协议/版本 加上 状态码组成

                响应状态码:服务器告诉客户端,浏览器本次的请求和响应的一个状态

                常见状态码:都是三位数

                        分类:

                        1xx:   服务器接收客户端消息,还没有接收完,等待一段时间后,发送1xx状态码

                        2xx:不是响应成功,200

                        3xx:重定向

                                302 :不是重定向,

                                304:访问缓存

                        4xx:客户端错误,从浏览器发过来请求错误(错误在浏览器中)

                                404:找不到对应的资源(页面、servlet)

                                405:表示方法不对,比如,客户端是get请求,请求到post方法中

                        5xx:服务器内部错误

                                500:服务器内部异常

        2、响应头:格式      头名称 :值

                常见的响应头:    

                        Content-Type;服务器告诉客户端本次响应的数据格式和编码格式

                                text/html;charset=utf-8

                        content-disposition:服务器告诉浏览器将来以什么格式打开响应体数据

                                in-line:在本页面打开,默认值

                                attrchment;filement = xxx:一附件形势打开响应体,下载使用

        3、响应空行:空行

        4、响应体:页面展示的内容

HttpServletResponse对象

        服务器用来响应数据到客户端的一个对象

        功能:

                1、设置响应行

                        设置响应行的状态码

                        void setStatus(int sc) 设置此响应的状态代 码。

                2、设置响应头

                        void setHeader(String name, String value) 用给定名称和值设置响应头。如果已经设置了头,则新值将重写以前的值。

                3、设置响应体

                        1,先获取输出流

                                ServletOutputStream getOutputStream() 返回适用于在响应中编 写二进制数据的 ServletOutputStream

                                PrintWriter getWriter() 返回可将字符 文本发送到客户端的 PrintWriter 对象                       

                        2,使用输出流,将数据输出到客户

HttpServletResponse重定向

        转发(forward)和重定向(redirect)的区别 ?

                1,转发请求1次,重定向请求2次

                2,转发url地址不改变,重定向url地址会改变

                3,转发不能访问服务器以外的资源,重定向可以

        void sendRedirect(String location) 使用指定重定 向位置 URL 将临时重定向响应发送到客户

          开启两个tomcat服务器,从tomcat1中的servlet,重 定向到tomcat2中的servlet

package com.javaweb.servlet3;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/ServletD")
public class ServletD extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("D资源被访问");
        //设置状态码
        //response.setStatus(302);
        //通过设置响应头在响应头设置一个叫location属性值为其他资源地址,
        // 浏览器拿到location,将这个资源地址拿到后重新请求
        //response.setHeader("location","/servlet/ServletE");



        //简写重定向方式
        response.sendRedirect("http://localhost:8081/hello/ServletF");

        //访问外部资源
       // response.setHeader("location","https://www.baidu.com/");
    }
}
package com.example.servlet_01;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/ServletF")
public class ServletF extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("F资源被访问");
    }
}
前端页面和servlet中资源路径的写法

        资源路径的写法 : 相对路径 和 绝对路径

        相对路径 : 指的是 以 ./或者 ../开头的地址,相对于自 己所在位置,去找资源位置

        写的时候,要明确目标资源地址,然后找到目标和 自身资源的相对关系

        比如 :

        写以上路径的时候,找到他们资源的相同的一个父 资源路径,然后看不同的部分有哪些

        比如上面的例子 : 在表单写路径的时候,用相对

        路径的写法 :

               <form action="./ServletlLogin"

                method="post">

        绝对路径 :指的是以 /开头的地址,指的是一个绝对的 资源的值,

                规则:判断定义的路径是给谁用的?

                如果是给客户端浏览器用的,从浏览器发出的请求,那么地址前需要加虚拟路径。

                如果是给服务器用的,比如服务器内部的转发,不需要加虚拟路径

                将来在项目中,一般可以使用相对路径的写法,如果要使用绝对路径的写法,将来虚拟路径发生了更改,代码中的虚拟路径也要更改。

               使用绝对路径的时候,为了避免修改虚拟路径带来的其他代码中资源路径的时候,可以使用动态或虚拟路径

                String getContextPath() 返回请求 URI 指示请 求上下文的那一部分

 设置响应体

        1,先获取输出流

                ServletOutputStream getOutputStream() 返 回适用于在响应中编写二进制数据的 ServletOutputStream

                PrintWriter getWriter() 返回可将字符文本发送 到客户端的 PrintWriter 对象

        2,使用输出流,将数据输出到客户端

package com.javaweb.servlet3;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/ServletF")
public class ServletF extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //做响应之前,设置响应头,确定编号格式,防止乱码
//        response.setCharacterEncoding("utf-8");
//        response.setHeader("content-text","text/html;charset=utf-8");
        response.setContentType("text/html;charset=utf-8");

        //获取输出流write对象
//        PrintWriter writer = response.getWriter();

//        writer.write("你好!");
//        writer.write("<h1>你好response响应内容</h1>");

        //使用字节输出流完成响应
        //获取字节输出流
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write("你好".getBytes("utf-8"));

    }
}
验证码的案例
<%--
  Created by IntelliJ IDEA.
  User: Daisy
  Date: 2023/10/12
  Time: 16:21
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>验证码</title>
</head>
<body>
    <div>
        <img src="/servlet/ServletCode" alt="" onclick="changeImage()">
        <a href="" onclick="changeImage()">看不清楚,换一张</a>
    </div>
</body>
<script>
    function changeImage(){
       //点击的时候,完成src地址的切换
        var imgElement = document.querySelector("img");
        imgElement.src = "/servlet/ServletCode?" + new Date()

    }
</script>
</html>
package com.javaweb.servlet3;

import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/ServletCode")
public class ServletCode extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //验证码图片的宽高
        int heigth = 50;
        int width = 100;

        //创建一个验证码图片对象
        BufferedImage image = new BufferedImage(width, heigth, BufferedImage.TYPE_INT_RGB);

        //给图片话内容
        Graphics g = image.getGraphics();//获取画笔
        g.setColor(Color.cyan);  //设置画笔颜色
        g.fillRect(0,0,width,heigth);  //画出区域

        g.setColor(Color.black);  //设置颜色
        g.drawRect(0,0,width,heigth); //画边框

        //生成验证码
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        //创建Random对象,生成随机4个索引,获取上面字符串的任意4个字符
        Random random = new Random();

        for (int i = 1; i <= 4; i++) {
            int index = random.nextInt(str.length());
            char ch = str.charAt(index);

            //每获取一个字符,就写一个字符带图片中,传入字符,传入坐标
            g.drawString(ch + "",width/5*i,heigth/2);

        }
        /*HttpSession session = request.getSession();
        session.setAttribute("code","验证码");*/
        //画干扰线
        g.setColor(Color.PINK);

        //画十根线
        for (int i = 0; i < 10; i++) {
            //获取画线的坐标
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(heigth);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(heigth);
            g.drawLine(x1,y1,x2,y2);

        }

        //将图片通过输出流写出去
        ImageIO.write(image,"jpeg",response.getOutputStream());


    }
}

ServletContext对象

概念 :ServletContext对象,是项目在启动的时候, 创建的一个web容器。每个web程序都会创建一个对应的 ServletContext对象,代表整个web应用工程,作用是可以 在服务器中完成通信(数据共享) 创建ServletContext对象方式: 1,通过request请求获取 request.getServletContext(); 2,通过当前servlet对象获取this.getServletContext()

package com.javaweb.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/ServletContext1")
public class ServletContext1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、通过request对象获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //通过当前servlet对象获取ServletContext
        ServletContext context= this.getServletContext();
        System.out.println(servletContext == context);

       

    }
}
ServletContext的功能
1,获取MIME类型

        MIME类型 : 在网络通信过程中,定义的一种文 件数据类型

        格式 : 大类型/小类型 比如: text/html , image/jpeg

        作用 :完成数据通信,一般都需要知道通信文件 的类型

        String getMimeType(String file) 返回指定文 件的 MIME 类型,如果 MIME 类型未知,则返回 null

package com.javaweb.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/ServletContext1")
public class ServletContext1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、通过request对象获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //通过当前servlet对象获取ServletContext
        ServletContext context= this.getServletContext();
        System.out.println(servletContext == context);

        //随便定义一个文件名
        String fileName = "123.jpg";

        String mimeType = context.getMimeType(fileName);

        System.out.println(mimeType);

    }
}
2、共享数据

        void setAttribute(String name, Object object) 将对象绑定到此 servlet 上下文中的给定属性名称。

        Object getAttribute(String name) 返回具有给定名 称的 servlet 容器属性,如果不具有该名称的属性,则返回 null

         ServletContext对象的作用范围 : 整个web程序的范围,所有用户所有请求的数 据,A存了后,B能取到,C也能取到

        不同的浏览器也能取到数据


@WebServlet("/ServletContextA")
public class ServletContextA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ServletContext context = request.getServletContext();
        context.setAttribute("message","大家共享的信息");
    }
}



@WebServlet("/ServletContextB")
public class ServletContextB extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ServletContext context = this.getServletContext();
        Object message = context.getAttribute("message");
        System.out.println("B获取内容:" + message);
    }
}

@WebServlet("/ServletContextC")
public class ServletContextC extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ServletContext context = this.getServletContext();
        Object message = context.getAttribute("message");
        System.out.println("C获取内容:" + message);
    }
}
3、获取文件真实路径(文件在服务器中地址)

        String getRealPath(String path) 为给定虚拟路径 返回包含实际路径的 String。

        测试方法的使用 :

                分别在src目录下,创建a.txt ,web目录下,创建 b.txt ,WEB-INF目录下创建c.txt

package com.javaweb.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/ServletContext2")
public class ServletContext2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、通过request对象获取ServletContext(真实地址)
        ServletContext servletContext = request.getServletContext();

        //通过文件资源路径,获取文件在服务器上的真实路径
        String pathb = servletContext.getRealPath("/b.text");//web目录下

        String pathc = servletContext.getRealPath("/WEB-INF/c.text"); //wen-inf目录下

        String patha = servletContext.getRealPath("/WEB-INF/classes/a.text");  //src下

        System.out.println(patha);
        System.out.println(pathb);
        System.out.println(pathc);

    }
}
4、加载properties资源

        InputStream getResourceAsStream(String path) 以 InputStream 对象的形式返回位于指定路径上的资源。

        在src下,创建一个properties文件

package com.javaweb.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

@WebServlet("/ServletContext3")
public class ServletContext3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1,通过request对象获取 ServletContext
        ServletContext servletContext = request.getServletContext();
        //获取src目录下的配置文件
        InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/user.properties");
        Properties pro = new Properties();
        pro.load(is);
        String userName = pro.getProperty("userName");
        String password = pro.getProperty("password");
        System.out.println(userName + "--" + password);


    }
}
文件下载的案例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>dowmload</title>
</head>
<body>
<a href="/servlet/ServletDownload?fileName=1.jpg">下载图片1.jpg</a><br>
<a href="/servlet/ServletDownload?fileName=2.jpg">下载图片2.jpg</a>

</body>
</html>
package com.javaweb.servletcontext;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/ServletDownload")
public class ServletDownload extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、获取文件名
        String fileName = request.getParameter("fileName");

        //2、获取文件在服务器上的位置
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + fileName);//img/1.jpg

        //3、将文件加载进内存
        FileInputStream fis = new FileInputStream(realPath);

        //4、做出响应

        //设置响应头,获取文件MIME类型
        String mimeType = servletContext.getMimeType(fileName);
        response.setHeader("content-type",mimeType);

        //设置文件以附件的形式打开
        response.setHeader("content-disposition","attachment;fileName=" + fileName);

        //5、获取输出流,完成数据传输
        ServletOutputStream os = response.getOutputStream();

        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fis.read(bytes)) != -1 ){
            os.write(bytes,0,len);
        }

        os.close();
        fis.close();


    }
}

乱码问题工具栏

package com.javaweb.servletcontext;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Base64;

public class DownloadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            filename =  "=?utf-8?B?" + Base64.getEncoder().encodeToString(filename.getBytes("utf-8"))+ "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值