欢迎来到 Kong Xiangqun 的博客

1、Servlet系列HTTP协议\tomcat\servlet

一、总体介绍

 

 

 

webserver:处理客户端提交过来的请求

A\B: 代表页面 response相应 请求的uri

有了servlet,问题再java代码里嵌入页面标签比较麻烦,因此有了jsp

随着时间发展 有了高级框架ssm,完成了请求的过程,并且动态生成页面

二、Tomcat

Tomcat服务器是一个免费的开放源代码的web应用服务器,属于轻量级应用服务器

我们之前javase运行一个代码,在IDEA里面run application运行了,自己能够控制什么时候运行的

对于客户端请求,我们不知道客户端什么时候发送请求,在webserver要准备一个长服务接收客户端请求

可以嵌入n个applet,比如有用户模块、商品模块、购物车模块,每一个模块都时一个applet,代码完成的逻辑放到webserver里

三、Tomcat的安装

/*
https://tomcat.apache.org/
*/

 

 

 可执行程序

 

 

 脚本启动和可执行程序启动,运行需要jdk支持

 

 

 conf目录:配置文件

比如配置端口:server.xml

 

 webapps

项目完成后打成war包

 

public class MyServlet extends HttpServlet {

会发现HttpServlet飘红了

 

 

 

 

 

 

 

 

 

 

 

 这就ok了

四、servlet基本原理

是一种Web服务器端编程技术。

是实现了特殊接口的Java类。(HttpServlet)

由支持Servlet的Web服务器调用和启动运行。

一个Servlet负责对应的一个或一组URL访问请求,并返回相应的响应内容。

 

使用:

创建一个普通java文件

Java文件的类名实现HttpServlet

重写service的方法

在WEB-INF下的web.xml中添加请求与servlet类的映射关系

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("first web project");
        System.out.println("my first web project");
    }
}
<?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-class配置项中添加servlet类的完全限定名  包名+类名-->
    <servlet>
        <servlet-name>myServlet</servlet-name>
        <servlet-class>com.mashibing.MyServlet</servlet-class>
    </servlet>
    <!--配置servlet跟请求的映射关系-->
    <servlet-mapping>
        <servlet-name>myServlet</servlet-name>
        <url-pattern>/first</url-pattern>
    </servlet-mapping>
</web-app>

需要把当前web tomcat包加进来

 

 

 

 

 

 

 

 

 有个问题,它是怎么找到的service,也没调doGet,确调用了service

xml配置也是只是指定到了com.mashibing.MyServlet

怎么实现的???

面向接口编程,继承了HttpServlet,实现了service方法

多态,父类对象指向子类引用

再写一个Myservice2.java

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hehe......");
    }
}

xml基于first加一个

<?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-name>second</servlet-name>
        <servlet-class>com.mashibing.MyServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>second</servlet-name>
        <url-pattern>/second</url-pattern>
    </servlet-mapping>
</web-app>

 

 

 1、servlet访问流程

 

url:http://localhost:8080/firstweb/first

组成:

  服务器地址:端口/虚拟项目名/servlet的别名

  uri:虚拟项目名/servlet别名

过程:

  浏览器发送请求到服务器,服务器根据请求URL地址中的URI信息在webapps目录下找到对应的项目文件夹,

  然后再web.xml中检索对应的servlet,找到后调用并执行servlet

2、servlet的生命周期

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "ServletLife")
public class ServletLife extends HttpServlet {

    /**
     * 完成servlet对象的初始化工作
     *  在servlet接受到第一次请求的时候创建对象
     *  生命周期:从第一次接受请求开始到服务器关系之后销毁
     *  当在web.xml文件中配置了<load-on-startup>1</load-on-startup>,在开启tomcat的时候就会创建servlet对象,中间的数值表示优先级的意思
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        System.out.println("init");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("servlet life");
        System.out.println("learn servlet life");
        System.out.println(req.getParameter("name"));
    }

    @Override
    public void destroy() {
        System.out.println("我被销毁了");
    }
}
<?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-name>life</servlet-name>
        <servlet-class>com.mashibing.ServletLife</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>life</servlet-name>
        <url-pattern>/life</url-pattern>
    </servlet-mapping>
</web-app>

运行之后发送请求创建对象执行init

停止运行时销毁对象, 服务器不停,对象一致存在

3、service、doGet、doPost方法的区别

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MethodServlet extends HttpServlet {
    public MethodServlet() {
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我是post");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println(10 / 0);
        System.out.println("我是get");
    }

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是service");
        super.service(req, resp);
    }
}
<?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-name>MethodServlet</servlet-name>
        <servlet-class>com.mashibing.MethodServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MethodServlet</servlet-name>
        <url-pattern>/method</url-pattern>
    </servlet-mapping></web-app>
</web-app>

如果发送post请求,写一个jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="method" method="get">
        用户名:<input type="text" name="name" value=""/><br/>
        密码:<input type="text" name="pwd" value=""/><br/>
        爱好:<br/>
        <input type="checkbox" name="fav" value="1">java
        <input type="checkbox" name="fav" value="2">c#
        <input type="checkbox" name="fav" value="3">php
        <input type="submit" value="登录">
    </form>
</body>
</html>

 

 

 总结:

/**
 *  Servlet类中可以有service方法,
 *      用来接受get或者post请求
 *      如果service和doGet或者doPost同时存在,那么默认会调用service方法
 *      如果同时又server,doGet和doPost方法,在service方法的实现中调用了super.service()会根据请求的方式跳转到doGet或者doPost
 *  doget方法:
 *      用来接受get请求
 *  doPost方法:
 *      用来接受post请求
 *
 * 总结:
 *      在编写servlet类的时候,不需要重新实现service方法,只需要重写doGet和doPost方法即可,用来接受post或者get请求
 *
 */

 

Service方法

  不管是get还是post请求方式,如果service方法存在,则优先执行service方法

doGet方法

  在没有service的情况下,如果是get请求,调用doGet方法

doPost方法

  在没有service的情况下,如果是post请求,调用doPost方法

常见错误:

404:访问资源不存在 请求路径跟web.xml中填写的请求不一致 请求路径的项目虚拟名称填写错误

405: 请求的方式跟servlet中支持的方式不一致

500:服务器内部错误 web.xml中servlet类的名称错误 servlet对应的处理方法中存在代码逻辑错误

 

五、request和response对象

1、request对象

请求行:

/**
 * HttpServletRequest用来存放客户端请求的参数
 *  请求行
 *  请求头
 *  请求体
 *
 *
 */
public class RequestServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("post请求");
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("get请求");
        //获取请求行数据
        //获取请求中的请求方式
        String method = request.getMethod();
        System.out.println(method);
        //获取请求的完整地址
        StringBuffer url = request.getRequestURL();
        System.out.println(url);
        //获取请求中的资源路径
        String uri = request.getRequestURI();
        System.out.println(uri);
        //获取请求中的协议
        String schema = request.getScheme();
        System.out.println(schema);
    }
}
<?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-class配置项中添加servlet类的完全限定名  包名+类名-->
    <servlet>
        <servlet-name>request</servlet-name>
        <servlet-class>com.mashibing.RequestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>request</servlet-name>
        <url-pattern>/request</url-pattern>
    </servlet-mapping>
</web-app>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="request" method="get">
        用户名:<input type="text" name="name" value=""/><br/>
        密码:<input type="text" name="pwd" value=""/><br/>
        爱好:<br/>
        <input type="checkbox" name="fav" value="1">java
        <input type="checkbox" name="fav" value="2">c#
        <input type="checkbox" name="fav" value="3">php
        <input type="submit" value="登录">
    </form>
</body>
</html>

 

 

 get提交

打印结果为:

/*
get请求
GET
http://localhost:8889/firstweb/request
/firstweb/request
http
*/

请求头

/**
 * HttpServletRequest用来存放客户端请求的参数
 *  请求行
 *  请求头
 *  请求体
 *
 *
 */
public class RequestServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("post请求");
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("get请求");
        //获取请求头数据
        //根据key获取value的值
        String userAgent = request.getHeader("User-Agent");
        System.out.println(userAgent);
        //获取请求头信息中的所有key的枚举对象
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String key = headerNames.nextElement();
            String value = request.getHeader(key);
//            System.out.println(headerNames.nextElement());
            System.out.println(key+":"+value);
        }
    }
}

 get提交

打印结果为:

/*
get请求
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
host:localhost:8889
connection:keep-alive
sec-ch-ua:" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
sec-ch-ua-mobile:?0
sec-ch-ua-platform:"Windows"
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site:same-origin
sec-fetch-mode:navigate
sec-fetch-user:?1
sec-fetch-dest:document
referer:http://localhost:8889/firstweb/method.jsp
accept-encoding:gzip, deflate, br
accept-language:zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6
cookie:JSESSIONID=89A18C7377FF29B4DC804D4615A95E76; Pycharm-4c27e691=9fe5ccdf-9cdc-403e-93fc-1f8f84d8d045; Pycharm-407b6bae=bb7b0f2c-184a-45bc-98de-14b230158790; Idea-b0806bee=73cc7b1f-4f5f-407d-b188-f3e761ca2000
*/

请求体

 

/**
 * HttpServletRequest用来存放客户端请求的参数
 *  请求行
 *  请求头
 *  请求体
 *
 *
 */
public class RequestServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("post请求");
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("get请求");
        //获取用户请求数据
        //无论请求方式是post还是get,获取用户数据的方式不变
        String name = request.getParameter("name");
        String pwd = request.getParameter("pwd");
        String fav = request.getParameter("fav");
        System.out.println(name+":"+pwd+":"+fav);

        //获取用户数据中的所有key
        Enumeration<String> parameterNames = request.getParameterNames();
        while(parameterNames.hasMoreElements()){
            System.out.println(parameterNames.nextElement());
        }

        //获取相同key的多个数据值,例如checkbox
        String[] parameterValues = request.getParameterValues("fav");
        for (String  str:parameterValues) {
            System.out.println("fav:"+str);
        }

        //其他常用方法
        //获取远程客户端的地址
        String remoteAddress = request.getRemoteAddr();
        //获取远程客户端的主机名称
        String remoteHost = request.getRemoteHost();
        //获取远程客户端的端口号
        int remotePort = request.getRemotePort();
        System.out.println(remoteAddress+":"+remoteHost+":"+remotePort);

        String localAddr = request.getLocalAddr();
        String localName = request.getLocalName();
        System.out.println(localAddr+":"+localName);
    }
}

 

 打印结果为:

/*
get请求
admin:fsadf:1
name
pwd
fav
fav:1
0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:1:57848
0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:1
*/

 

2、response对象

HttpServletResponse对象是服务器的响应对象,这个对象中封装了向客户端发送数据,发送响应头,发送响应状态码的方法。

public class ResponseServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("this is post");
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("this is get");
        //设置响应头,按照key-value键值对的方式来设置,如果存在相同的key,会把value的值覆盖
        response.setHeader("hehe","haha");
        response.setHeader("hehe","heihei");
        //设置响应头,按照key-value键值对的方式来设置,如果存在相同的key,不会覆盖值
        response.addHeader("beijing","shanghai");
        response.addHeader("beijing","guangzhou");

        //服务端返回的对象数据要按照一定的格式要求进行渲染,只有是html格式才会识别标签
//        response.setHeader("Content-Type","text/html");
        response.setHeader("Content-Type","text/plain");
//        response.setContentType("text/html");
        //设置响应状态码
//        response.sendError(404,"not found");
        response.getWriter().write("<b>java is easy</b>");

    }
}
<?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-class配置项中添加servlet类的完全限定名  包名+类名-->
        <servlet>
        <servlet-name>response</servlet-name>
        <servlet-class>com.mashibing.ResponseServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>response</servlet-name>
        <url-pattern>/response</url-pattern>
    </servlet-mapping>
</web-app>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="response" method="post">
        用户名:<input type="text" name="name" value=""/><br/>
        密码:<input type="text" name="pwd" value=""/><br/>
        爱好:<br/>
        <input type="checkbox" name="fav" value="1">java
        <input type="checkbox" name="fav" value="2">c#
        <input type="checkbox" name="fav" value="3">php
        <input type="submit" value="登录">
    </form>
</body>
</html>

/*
this is post
this is get
*/

 3、用户登陆示例:

/*
登录小项目流程:
    1、使用原生的方式生成页面
    2、客户端先发送请求,得到要登录的页面
    3、用户填写相应的用户数据,发送请求给服务端
    4、服务端接受到请求后进行逻辑处理
    5、服务端将处理之后的结果返回给客户端


分层:
    web项目中包含层次的概念
    control
    service
    dao
*/

 

 

control: 接收用户的请求, 并解析参数

service: 代码的逻辑处理

dao: 与数据库交互

entity: 用户类

control 调 service, service调dao

从里到外一次填写代码

 

dao下代码

public interface UserService {

    public User checkUser(User user);
}
/**
 * 跟数据库发生交互
 */
public class UserDaoImpl implements UserDao {
    @Override
    public User checkUser(User user) {

        //定义连接的对象
        Connection conn = null;
        PreparedStatement pstmt  = null;
        ResultSet rs = null;
        User u = null;
        try {
            //加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/login","root","123456");
            //获取预处理块
            pstmt = conn.prepareStatement("select * from user where name = ? and pwd =?");
            //给?赋值
            pstmt.setString(1,user.getName());
            pstmt.setString(2,user.getPwd());
            //执行sql语句
            rs = pstmt.executeQuery();
            //从resultset中获取结果值
            while (rs.next()){
                u = new User(rs.getInt("id"),rs.getString("name"),rs.getString("pwd"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return u;
    }
}

 

 

 service下代码

public interface UserService {

    public User checkUser(User user);
}
import com.mashibing.dao.UserDao;
import com.mashibing.dao.impl.UserDaoImpl;
import com.mashibing.entity.User;
import com.mashibing.service.UserService;

public class UserServiceImpl  implements UserService {

    UserDao userDao = new UserDaoImpl();
    @Override
    public User checkUser(User user) {
        return userDao.checkUser(user);
    }
}

control下代码

public class LoginServlet extends HttpServlet {

    UserService userService = new UserServiceImpl();
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("gbk");
        //获取请求数据
        String name = request.getParameter("name");
        String pwd = request.getParameter("pwd");
        //封装对象
        User user = new User(name,pwd);
        //调用service进行逻辑处理
        User u = userService.checkUser(user);
        System.out.println(u);

        if(u!=null){
//            response.getWriter().write("success");
//            request.getRequestDispatcher("hello").forward(request,response);
            response.sendRedirect("hello");
        }else{
//            response.getWriter().write("failure");
//            //设置响应编码
//            response.setContentType("text/html");
//            //获取响应的输出流对象
//            PrintWriter out = response.getWriter();
//            out.write("<html>");
//            out.write("<head>");
//            out.write("</head>");
//            out.write("<body>");
//            out.write("<form action='login' method='get'>");
//            out.write("name:<input type='text' name='name' value='' ><br/>");
//            out.write("pwd:<input type='text' name='pwd' value=''><br/>");
//            out.write("<input type='submit' value='login'>");
//            out.write("</form>");
//            out.write("</body>");
//            out.write("</html>");
            //设置参数
            request.setAttribute("str","用户名或者密码错误");
            //请求servlet的时候,写相对路径,同时后续不需要逻辑代码的处理, 请求转发
            request.getRequestDispatcher("page").forward(request,response);
            return ;
        }
    }
}

 

PageServlet.java 返回用户输入框

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class PageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("接受到客户端的请求,返回响应的登录页面");

        String str = (String) request.getAttribute("str")==null?"":(String) request.getAttribute("str");
        System.out.println(str);
        //设置响应编码
        response.setContentType("text/html");
        //获取响应的输出流对象
        PrintWriter out = response.getWriter();
        out.write("<html>");
        out.write("<head>");
        out.write("</head>");
        out.write("<body>");
        out.write("<font color='red' size='20px'>"+str+"</font>");
        out.write("<form action='login' method='get'>");
        out.write("name:<input type='text' name='name' value='' ><br/>");
        out.write("pwd:<input type='text' name='pwd' value=''><br/>");
        out.write("<input type='submit' value='login'>");
        out.write("</form>");
        out.write("</body>");
        out.write("</html>");
    }
}
<?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-name>PageServlet</servlet-name>
        <servlet-class>com.mashibing.control.PageServlet</servlet-class>
    </servlet>


    <servlet-mapping>
        <servlet-name>PageServlet</servlet-name>
        <url-pattern>/page</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.mashibing.control.LoginServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.mashibing.control.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

 

4、servlet乱码问题解决

上面写的小程序没用到中文,如果中文就会出现乱码

/**
 * 处理乱码问题的方式
 *  1、get请求
 *      1、获取字符串之后使用new String(name.getBytes("iso-8859-1"),"utf-8")
 *      2、设置request的编码格式,request.setCharacterEncoding("utf-8"); 同时在server.xml中添加useBodyEncodingForURI=true的属性
 *      3、在server.xml中添加URIEncoding="utf-8"
 *  2、post请求
 *      1、request.setCharacterEncoing("utf-8")
 *  3、response响应编码
 *       response.setCharacterEncoding("gbk");
 */
public class CharsetServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        System.out.println("post");
        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("name");
        System.out.println(name);
        response.setCharacterEncoding("gbk");
        response.getWriter().write("欢迎你!");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        System.out.println("get");
        //设置请求的编码格式
//        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("name");
//        System.out.println(new String(name.getBytes("iso-8859-1"),"utf-8"));
        System.out.println(name);
    }
}
<?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-name>CharsetServlet</servlet-name>
        <servlet-class>com.mashibing.CharsetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CharsetServlet</servlet-name>
        <url-pattern>/charset</url-pattern>
    </servlet-mapping>
</web-app>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
 <form action="charset" method="post">
   <input type="text" name="name" value="">
   <input type="submit" value="login">

 </form>
  </body>
</html>

六、servlet request的作用域

我们上面登陆的例子, 输入完用户名密码, 如果错误, 应该有个提示信息,用户名错误之类的

我们第一次请求请求的是

 

 

 返回一个页面

 

 

 输入完信息呢第二次请求

 

 

 如果错误, 请求转发 请求page

 

 

 为了实现不同servlet之间的数据共享, 通过 request.setAttribute 设置

可以在page里拿到配置

 

 

 第一次获取的是null, 所以要做一个判断

 

七、servlet重定向

上面我们请求错误,做了一个请求转发, 那请求成功后,我们也不能直接返回一个success

应该跳转到某一个页面里面

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("gbk");
        String name = request.getParameter("name");
        PrintWriter out = response.getWriter();
        out.write("<html>");
        out.write("<head>");
        out.write("</head>");
        out.write("<body>");
        out.write("<h1>欢迎"+name+"登录<h1>");
        out.write("</body>");
        out.write("</html>");
    }
}

可以请求转发

 

 

 如果频繁点刷新,每个请求都带name password,每一次点击都相当于是两个请求

正常点击只需要刷新欢迎页面就可以,不用登陆请求

所以就需要重定向

 

 

 

 

 

 

七、cookie、session

1、cookie

 如何解决重定向之后两次请求null的问题

 

 

 就要用到cookie

http协议无状态

import javax.servlet.http.Cookie;
import java.io.IOException;

/**
 * cookie:用来处理客户端发送不同请求的时候如何使用相同的参数信息
 *  cookie的使用
 *        Cookie cookie = new Cookie("00001","beijing");
 *        response.addCookie(cookie);
 *        设置cookie的参数
 *        cookie.setMaxAge( int seconds)
 *        cookie.setPath(String  url)
 *        获取cookie对象
 *        Cookie[] cookies = request.getCookies()
 *
 *  特点:
 *      1、cookie是保存在浏览器端的数据名称
 *      2、cookie分类:临时cookie,默认是存储在内存中的,所以当浏览器关闭的时候,cookie自动失效
 *                      持久化cookie,保存在浏览器的某个存储目录,当时间过期之后,才会失效
 *      3、每一个cookie对象中保存一个key-value键值对的数据,想要存储多个k-v数据,需要创建多个Cookie对象
 *
 */
public class CookieServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("gbk");


        //创建Cookie对象
        Cookie cookie = new Cookie("00001","beijing");
        Cookie cookie1 = new Cookie("0002","shanghai");
        //给cookie对象添加时间有效期,单位是s
        cookie.setMaxAge(3*24*3600);
        //给cookie设置固定路径值
        cookie1.setPath("/cookie/abc");
        //将cookie设置到response对象中
        response.addCookie(cookie);
        response.addCookie(cookie1);
        response.getWriter().write("学习cookie");
    }
}

 

 

 

 

 

 重新发送一个请求

 

 

 Cookie中也存在,保存成功了,浏览器重新打开也会存在

我么定义的cookie1是临时cookie所以没有

因为我们设置了setPath

 

 

 这样就两个都会有了

 

现在已经设置好了,怎么获取数据呢??

public class GetCookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("gbk");

        //获取cookie对象
        Cookie[] cookies = request.getCookies();
        if(cookies.length>0){
            for (Cookie c: cookies) {
                String key = c.getName();
                String value = c.getValue();
                System.out.println(key+":"+value);
            }
        }
    }
}

 

 

 要判断getCookies()的长度, 否则直接访问会报空指针

功能实现:

实现用户的一周免登录

/*
用户免登录实现:
    1、用户发送验证cookie信息的请求,编写对应的servlet进行处理
    2、如果包含cookie,直接跳转到成功页面
    3、如果不包含cookie信息,直接跳转到登录页面
*/

第一次登陆成功需要创建cookie, 返回给客户端

 

 

 在LoginServlet接收请求后通过service逻辑处理, 返回不为null后成功, 设置cookie, 跳转hello界面

 

 

 

 

 

 UserDaoImpl 下的 getUserById方法

 

 

 

总结流程

url 输入/cookie 判断cookie是否存在, 不存在跳转page登陆界面, 存在cookie, 判断cookie中的key值是否为登陆成功设置的key值(uid: 1)

存在, 则获取key对应的value, 通过value值调用servers逻辑判断, 判断成功返回hello界面

2、session

概念:

  Session表示会话,在一段时间内,用户与服务器之间的一系列的交互操作。

  session对象:用户发送不同请求的时候,在服务器端保存不同请求共享数据的存储对象

特点

  Session是依赖cookie技术的服务器端的数据存储技术

  由服务器进行创建

  每个用户独立拥有一个session对象

  默认存储时间是30分钟

用户使用浏览器第一次向服务器发送请求, 服务器在接受到请求后, 调用对应的 Servlet 进行处理。 在处理过程中会给用户创建一个 session 对象, 用来存储用户请求处理相关的公共数据, 并将此 session 对象的 JSESSIONID 以 sessoin 的形式存储在浏览器中(临时存储, 浏览器关闭即失效)。 用户在发起第二次请求及后续请求时, 请求信息中会附带 JSESSIONID, 服务器在接收到请求后,调用对应的 Servlet 进行请求处理, 同时根据 JSESSIONID 返回其对应的 session 对象

 

 

 

创建sessoin对象

  HttpSession session = request.getSession()

向Session对象中添加值

  sessoin.setAttribute(String name,Object object)

获取Session中的值

  session.getAttribute(String name)

设置sessoin属性

  session.setMaxInactiveInterval(5)//设置存活时间

  session.invalidate(); //session强制失效

import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 *
 * session
 *  作用:
 *      解决相同用户发送不同请求时的数据共享问题
 *  特点:
 *      1、服务器端存储共享数据的技术
 *      2、session需要依赖cookie技术
 *      3、每个用户对应一个独立的session对象
 *      4、每个session对象的有效时长是30分钟
 *      5、每次关闭浏览器的时候,重新请求都会开启一个新的session对象,因为返回的JSESSIONID保存在浏览器的内存中,是临时cookie,所以关闭之后自然消失
 *  使用:
 *      获取session对象
 *      HttpSession session = request.getSession();
 *      修改session会话的保持时间
 *      session.setMaxInactiveInterval(int second);
 *      设置强制失效
 *      session.invalidate();
 */
public class SessionServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //设置请求响应的编码格式
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        System.out.println("接受到请求get");
        //获取session对象
        HttpSession session = request.getSession();
        //设置session的有效时长
//        session.setMaxInactiveInterval(5); 过期重新获取session_id
        //getid方法拿到JSESSIONID
        System.out.println(session.getId());
        //设置session强制失效
//        session.invalidate(); 每次请求都想要一个新的session对象
        //向session中设置参数
        session.setAttribute("111","zhangsan");
        response.getWriter().write("学习session");
    }
}

 

 

 相应头中会有一个Set-Cookie

控制台打印

 

 

 下次访问就会携带cookie_id

 

获取session中的参数值

public class SessionServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //获取session对象
        HttpSession session= request.getSession();
        //获取session中的参数值
        String str = (String) session.getAttribute("111");
        System.out.println(str);
        response.getWriter().write(str);
    }
}

 

 

 

 

 

 

如果没有访问session,直接访问session2,就会引起空指针异常

用session解决之前出现过的null问题

 

 

 第一次登陆成功创建session对象,设置参数值

 

 

 

 

 

 hello页面拿到name值

这里没有完善判断第二次发送请求拿到cookie_id 是否与 session_id是否相等,只是简单演示了一下session

八、servletContext对象与ServletConfig对象

1、servletContext对象

request: 把客户端的请求参数包装到request对象里, 不同servlet流转的数据共享问题

cookie: 把数据保存在客户端的一项技术

session: 同一个用户发送不同请求的数据共享问题, 数据放到服务端

思考: 不同用户的数据共享怎么办???

不同用户为什么需要数据共享

浏览技术贴吧时, 会有当前有 多少人 访问

也不能放到cookie, 也不能放到session, 一个放到客户端,一个是每个用户的共享对象

用ServletContext来处理

仿照session的思路, 一个用户发送不同请求时, 获取到的是同一个对象

不同用户请求同一个服务器,能不能从同一台服务器里获取到同一个对象呢

 

运行在JVM上的每一个web应用程序都有一个与之对应的Servlet上下文(Servlet运行环境)

Servlet API提供ServletContext接口用来表示Servlet上下文,

ServletContext对象可以被web应用程序中的所有servlet访问

ServletContext对象是web服务器中的一个已知路径的根

 

ServletContext 对象由服务器进行创建, 一个项目只有一个对象。

不管在项目的任意位置进行获取得到的都是同一个对象,

那么不同用户发起的请求获取到的也就是同一个对象了, 该对象由所以用户共同拥有。

 

 

 

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 *
 * Servletcontext:
 *      作用:
 *          解决不同用户的数据共享问题
 *      特点:
 *          1、由服务器创建
 *          2、所有用户共享同一个ServletContext对象
 *          3、所有的servlet都可以访问到同一个ServletContext中的属性
 *          4、每一个web项目对应的是一个ServletContext
 *      用法:
 *          获取servletcontext对象
 *          //1
 *         ServletContext context = this.getServletContext();
 *         //2
 *         ServletContext context1 = this.getServletConfig().getServletContext();
 *         //3
 *         ServletContext context2 = request.getSession().getServletContext();
 *          向ServletContext对象中设置属性值
 *          context.setAttribute(String key,Object value)
 *          获取属性值
 *          context.getAttribute(String key)
 *          其他用途
 *          1、获取web,xml中配置的公共属性
 *          在web.xml中添加公共属性
 *              <context-param>
 *                  <param-name>beijing</param-name>
 *                  <param-value>beautiful</param-value>
 *              </context-param>
 *         context.getInitParameter(String key)
 *         如果有多组公共属性,使用多个context-param标签
 *         2、获取项目的虚拟目录路径
 *         context.getContextPath()
 *         3、获取某个资源的绝对路径
 *         context.getRealPath(String filename)
 */
public class ServletContextServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //获取servletContext对象
        //1
        ServletContext context = this.getServletContext();
        //2
        ServletContext context1 = this.getServletConfig().getServletContext();
        //3
        ServletContext context2 = request.getSession().getServletContext();

        System.out.println(context==context1);
        System.out.println(context == context2);
        System.out.println(context1==context2);

        //设置属性值
        context.setAttribute("111","zhangsan");

        //从web.xml中获取参数值
        String value = context.getInitParameter("china");
        System.out.println(value);
        //获取某个文件的绝对路径
        String path = context.getRealPath("web.xml");
        System.out.println(path);

        //获取web项目的上下文路径
        String path2 = context.getContextPath();
        System.out.println(path2);
    }
}

在web.xml中配置属性

打印结果为:

/*
true
true
true
great
C:\kxq\E_file\java\code\servletcontext\out\artifacts\servletcontext_war_exploded\web.xml
/context
*/

 打印的context 指的是

 

测试是否共享

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

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String value = (String) context.getAttribute("111");
        System.out.println(value);
    }
}

 

 

 打印结果为:

 

 

 

 

 

示例:

实现网站计数器

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class NumServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码格式
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //获取Servletcontext对象
        ServletContext context = this.getServletContext();
        //获取属性值
        Integer num = (Integer) context.getAttribute("num");
        if(num==null){
            context.setAttribute("num",1);
        }else{
            //实现每次访问加1的功能
            num++;
            //将num设置回servletcontext对象中
            context.setAttribute("num",num);
        }

        //获取输出对象
        PrintWriter out = response.getWriter();
        out.write("<html>");
        out.write("<head>");
        out.write("</head>");
        out.write("<body>");
        out.write("用户访问的次数是"+context.getAttribute("num")+"次");
        out.write("</body>");
        out.write("</html>");
    }
}

用户第一次访问没有num, 需要判断, 以后的所有用户共享上下文, 都有num了, 都会走到else 进行 ++ 操作

 

 

 

 

 

 关闭浏览器也无所谓会继续加

2、ServletConfig对象

思考:使用ServletContext对象可以获取web.xml中的全局配置文件,

在web.xml中,每个Servlet也可以进行单独的配置,那么该怎么获取配置信息呢?

使用ServletConfig对象

 

作用:

ServletConfig对象是Servlet的专属配置对象,每个Servlet都单独拥有一个ServletConfig对象 ,用来获取web.xml中的配置信息

使用: 获取ServletConfig对象 获取web.xml中的servlet配置信息

<?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-name>ServletConfigServlet</servlet-name>
        <servlet-class>com.mashibing.ServletConfigServlet</servlet-class>
        <init-param>
            <param-name>china</param-name>
            <param-value>beijing</param-value>
        </init-param>
        <init-param>
            <param-name>hebei</param-name>
            <param-value>shijiazhuang</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletConfigServlet</servlet-name>
        <url-pattern>/config</url-pattern>
    </servlet-mapping>
</web-app>
/**
 *
 * Servletconfig
 *      作用:
 *          方便每一个servlet获取自己单独的属性配置
 *      特点:
 *          1、每一个servlet单独拥有一个servletConfig对象
 *      使用:
 *          获取对象
 *          ServletConfig config = this.getServletConfig();
 *          获取值
 *          config.getInitParameter("china");
 *          获取所有的key值
 *          config.getInitParameterNames();
 */
public class ServletConfigServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取对象
        ServletConfig config = this.getServletConfig();
        String value = config.getInitParameter("china");
        System.out.println(value);
        //获取所有的key
        Enumeration<String> initParameterNames = config.getInitParameterNames();
        while (initParameterNames.hasMoreElements()){
            String key = initParameterNames.nextElement();
            String value2 = config.getInitParameter(key);
            System.out.println(key+"----"+value2);
        }
    }
}

 

 打印结果为:

/*
beijing
hebei----shijiazhuang
china----beijing
*/

 

posted @ 2022-04-25 21:05  kongxiangqun20220317  阅读(60)  评论(0编辑  收藏  举报