jsp + servle复习(C02)

4 篇文章 0 订阅
4 篇文章 0 订阅

C02_D02_UrlRewriting
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>会话管理技术->URL重写(URL Rewriting)</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
    </head>
    <body>
        
        <div class="container">

            <h1 class="text-center text-primary">会话管理技术->URL重写(URL Rewriting)</h1>
            <hr>
            <br>
            
            <form action="profile.jsp" class="form-inline">
                <label for="xuehao">学号: </label>
                <input type="text" name="rollno" id="xuehao" class="form-control">&nbsp;
                <input type="submit" value="查询个人信息" class="btn btn-sm btn-primary">
            </form>
            
        </div>
    </body>
</html>

在这里插入图片描述
点击查询个人信息后:
在这里插入图片描述
点击查看个人成绩单后:
在这里插入图片描述
C02_D03_Cookie
在这里插入图片描述
在这里插入图片描述
login.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录首页</title>
        
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>  

        <!--Cookie: 是Web程序创建放到客户端的小型文本文件,用于存储少量的用户信息-->
        <!--Cookie由服务器端创建,和响应一起发送到客户端,存放在客户端的小型文本文件-->
        
        <div class="container">

            <form action="ls" class="form-inline text-center loginForm bg-primary">
                <h1 class="text-center">用户登录</h1>
                <hr>
                <br>
                账&nbsp;号: <input type="text" name="username" class="form-control">
                <br><br>
                密&nbsp;码: <input type="password" name="password" class="form-control">
                <br><br>

                &nbsp;&nbsp;
                <input type="submit" value="登录" class="btn btn-sm btn-default">
            </form>
            
        </div>
    </body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html>
    <head>
        <title>登录失败页面</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <br>
        <h1 class="msg-warning">
            <!--点击超链接可以执行javascript代码,javascript提供对象history-->
            <!--history对象的back()函数实现退回上一个页面,也就是返回的效果-->
            <!--如果点击超链接想执行javascript,直接在href中编写javascript:js代码即可-->
            账户或密码错误,请<a href="javascript:history.back();">返回</a>重新登录!
        </h1>
        <hr>

    </body>
</html>

在这里插入图片描述

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录成功</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">
            
            <h1 class="text-center text-success">登录成功,XXX,欢迎进入教务系统</h1>
            <a href="#" class="logout">退出登录</a>

            <hr><br>
            
            <ul class="list-menu">
                <li><a href="profile.jsp">查看个人信息</a></li>
            </ul>

        </div>
    </body>
</html>

LoginServlet

package com.qdu.servlet;

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

@WebServlet("/ls")
public class LoginServlet extends HttpServlet {

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

        String uname = req.getParameter("username");
        String pwd = req.getParameter("password");

        //这里设定用户名是anna,密码是1234,则登录成功
        if ("anna".equals(uname) && "1234".equals(pwd)) {
            //HttpServletResponse的sendRedirect()实现重定向
            //也就是重定向到另一个页面作为响应内容
            resp.sendRedirect("success.jsp");
        } else {
            resp.sendRedirect("fail.html");
        }
    }
}

C02_D03_Cookie
在这里插入图片描述
login.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录首页</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
        <style>
            label:hover{
                cursor: pointer;
                text-decoration: underline;
            }
        </style>
    </head>
    <body>  

        <div class="container">
            
            <br>

            <p class="text-danger">
                * 本程序没有连接数据库,使用账户anna和密码1234可以通过登录验证 <br>
                * 本程序使用Cookie实现记住用户密码的功能
            </p>
            
            <%
                //JSP提供隐式对象request,表示该页面收到的请求
                //通过请求对象可以获取到该程序放的所有Cookie,以Cookie数组的形式返回
                Cookie[] cks=request.getCookies();
                //也可能一个Cookie都没有,则无需遍历Cookie数组,直接返回
                if(null==cks) return;
                
                //定义两个变量,用于存储Cookie的值
                String uname="";
                String upwd="";
                
                //如果有Cookie,则遍历Cookie数组,读取Cookie的值即可
                for(Cookie c:cks){ //对于数组cks中的每个Cookie对象
                    //如果当前遍历的cookie的名称是username
                    if("username".equals(c.getName()))
                        uname=c.getValue(); //获取其值,存储到变量uname中
                    else if("userpwd".equals(c.getName())) //如果当前遍历的cookie的名称是userpwd
                        upwd=c.getValue();  //获取其值,存储到变量upwd中
                }
            %>

            <!--            
            这里将两个文本框的值分别设置为两个Cookie的值
            如果有对应的Cookie值,则会显示在文本框中
            如果没有对应的Cookie值,则显示空白,也就是记住密码的功能
            -->
            
            <form action="ls" class="form-inline text-center loginForm bg-primary">
                <h1 class="text-center">用户登录</h1>
                <hr>
                <br>
                账&nbsp;号: <input type="text" name="username" value="<%=uname%>" class="form-control">
                <br><br>
                密&nbsp;码: <input type="password" name="password" value="<%=upwd%>" class="form-control">
                <br><br>
                <input type="checkbox" id="remember" name="rem" value="Y">
                <label for="remember">记住密码</label>
                &nbsp;&nbsp;
                <input type="submit" value="登录" class="btn btn-sm btn-default">
            </form>

        </div>
    </body>
</html>

在这里插入图片描述
web.html

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <!--welcome-file-list标记用于定义程序的欢迎文件列表-->
    <!--欢迎文件可以设置多个,如果前面的页面不可用,则会使用后面的页面-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
<!--        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>home.html</welcome-file>
        <welcome-file>home.jsp</welcome-file>-->
    </welcome-file-list>
</web-app>

在这里插入图片描述
LoginServlet

package com.qdu.servlet;

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

@WebServlet("/ls")
public class LoginServlet extends HttpServlet {

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

        String uname = req.getParameter("username");
        String pwd = req.getParameter("password");

        //创建Cookie,用于存储少量的用户信息
        //Cookie是一种客户端技术,用于存储少量的用户信息
        //Cookie是服务器端创建,发送到客户端,存储在客户端的小型文本文件
        //使用Cookie类创建和操作Cookie
        //Cookie是以键-值对的形式存储数据,键和值都是字符串
        //一个Cookie只能用于存储一项信息
        //默认情况下Cookie是浏览器会话范围的cookie,随着浏览器关闭,Cookie会立刻被删除
        Cookie ck1 = new Cookie("username", uname);
        Cookie ck2 = new Cookie("userpwd", pwd);

        String rem = req.getParameter("rem");
        
        //可以设置Cookie的最大时间,也就是Cookie存在客户端多久,单位是秒
        //如果设置了最大时间,则在到期前,即使关闭浏览器再打开,Cookie依然会存在
        if ("Y".equals(rem)) { //如果用户选择记住密码,则设置Cookie 存在7天
            ck1.setMaxAge(7 * 24 * 60 * 60);
            ck2.setMaxAge(7 * 24 * 60 * 60);
        }else{ //否则立刻删除Cookie
            //考虑到用户可能上次记住,存储了cookie,这次选择不记住,则该种情况下要删除Cookie
            //Cookie类没有提供专门的方法用于删除一个Cookie
            ck1.setMaxAge(0); //最大时间为0意味着立刻删除Cookie
            ck2.setMaxAge(0);
        }

        //Cookie需要存储到客户端,所以需要和响应一起发送到客户端并存储在客户端
        //只不过是作为响应的报头/标头发送给客户端的
        //必须在设置好Cookie之后,将Cookie添加到响应对象中,才能发送到客户端
        resp.addCookie(ck1);
        resp.addCookie(ck2);

        if ("anna".equals(uname) && "1234".equals(pwd)) {
            //HttpServletResponse的sendRedirect()方法用于重定向到指定页面作为响应内容
            resp.sendRedirect("success.jsp"); //succeed
        } else {
            resp.sendRedirect("fail.html");
        }
    }
}

success.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录成功</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">
            
            <!--Cookie是服务器端创建,发送到客户端的小型文本文件,用于存储少量的用户信息-->
            <!--一旦Cookie保存在客户端,后续再次请求该程序的任何资源,Cookie会随着请求-->
            <!--一起被发送返回给服务器,这样服务器端可以读取Cookie的信息-->
            
            <%
                //JSP提供隐式对象request,表示该页面收到的请求
                //通过请求对象可以获取到该程序放的所有Cookie,以Cookie数组的形式返回
                Cookie[] cks=request.getCookies();
                //也可能一个Cookie都没有,则无需遍历Cookie数组,直接返回
                if(null==cks) return;
                
                //定义两个变量,用于存储Cookie的值
                String uname="";
                String upwd="";
                
                //如果有Cookie,则遍历Cookie数组,读取Cookie的值即可
                for(Cookie c:cks){ //对于数组cks中的每个Cookie对象
                    //如果当前遍历的cookie的名称是username
                    if("username".equals(c.getName()))
                        uname=c.getValue(); //获取其值,存储到变量uname中
                    else if("userpwd".equals(c.getName())) //如果当前遍历的cookie的名称是userpwd
                        upwd=c.getValue();  //获取其值,存储到变量upwd中
                }
            %>
            
            <br>用户:<%=uname%>
            <br>密码:<%=upwd%>
            
            <h1 class="text-center text-success">登录成功,<%=uname%>,欢迎进入教务系统</h1>
            <a href="#" class="logout">退出登录</a>

            <hr>
            <br>
            
            <a href="profile.jsp">查看个人信息</a>

        </div>
    </body>
</html>

在这里插入图片描述
profile.jsp


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>个人信息</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
    </head>
    <body>

        <div class="container">

            <h1 class="text-center text-warning">个人信息</h1>
            <hr>
            <br>

            <%
                //JSP提供隐式对象request,表示该页面收到的请求
                //通过请求对象可以获取到该程序放的所有Cookie,以Cookie数组的形式返回
                Cookie[] cks=request.getCookies();
                //也可能一个Cookie都没有,则无需遍历Cookie数组,直接返回
                if(null==cks) return;
                
                //定义两个变量,用于存储Cookie的值
                String uname="";
                String upwd="";
                
                //如果有Cookie,则遍历Cookie数组,读取Cookie的值即可
                for(Cookie c:cks){ //对于数组cks中的每个Cookie对象
                    //如果当前遍历的cookie的名称是username
                    if("username".equals(c.getName()))
                        uname=c.getValue(); //获取其值,存储到变量uname中
                    else if("userpwd".equals(c.getName())) //如果当前遍历的cookie的名称是userpwd
                        upwd=c.getValue();  //获取其值,存储到变量upwd中
                }
            %>
            
            <br>用户:<%=uname%>
            <br>密码:<%=upwd%>

        </div>
    </body>
</html>

C02_D04_Session
在这里插入图片描述
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录首页</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>  

        <div class="container">

            <form action="ls" class="form-inline text-center loginForm bg-cyan">
                <h1 class="text-center">用户登录</h1>
                <hr>
                <br>

                学&nbsp;号: <input type="text" name="rollno" class="form-control">
                <br><br>
                密&nbsp;码: <input type="password" name="pwd" class="form-control">
                <br><br>
                <input type="submit" value="登录" class="btn btn-sm btn-default">

            </form>

        </div>
    </body>
</html>

success.jsp

<%@page import="com.qdu.pojo.Student"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登录成功</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">

            <h1 class="text-center text-success">欢迎进入教务系统</h1>
            
            <%
                //根据属性名获取会话中的属性值
                //如果需要转换到对应类型,需要强制转换
                Student s=(Student)session.getAttribute("student");
            %>
            
            <a href="#" class="info">当前登录:<%=s.getSname() %> </a>
            <a href="los" class="logout">退出登录</a>

            <hr><br>
            
            <!--jsp提供隐式对象session,用于在jsp页面上访问当前的会话对象-->

            <ul class="list-menu">
                <li><a href="profile.jsp">查看个人信息</a></li>
                <li><a href="#">查询班级课表</a></li>
                <li><a href="#">查看个人成绩</a></li>
            </ul>

        </div>
    </body>

在这里插入图片描述
在这里插入图片描述
profile.jsp

 
<%@page import="com.qdu.pojo.Student"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>个人信息</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">

            <h1 class="text-center text-warning">个人信息</h1>
            <hr>
            <br>

            <div class="content-container">

                <%
                    //放入会话的数据可以在程序中的任何jsp页面或servlet中获取到
                    //因为只要会话没有结束,则数据会一直存在于会话中,除非手动清除
                    Student stu=(Student)session.getAttribute("student");
                %>
                
                <br>学号: <%=stu.getSrollno() %>
                <br>姓名: <%=stu.getSname()%>
                <br>性别: <%=stu.getSgender()%>
                <br>密码: <%=stu.getSpassword()%>
                <br>班级: <%=stu.getSbatch()%>
                <br>
                <!--title用于指定鼠标悬到图片上的提示文字-->
                <!--alt用于指定图片无法正常显示的时候的替代文字-->
                <img class="photo" width="150" height="150" 
                     src="images/<%=stu.getSrollno()%>.jpg" 
                     alt="<%=stu.getSname()%>" 
                     title="<%=stu.getSname()%>">

            </div>
        </div>
    </body>
</html>

DatabaseUtil

package com.qdu.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * 数据库工具类,帮助获取到对应数据库的连接和关闭连接
 *
 * @author Anna
 */
public class DatabaseUtil {

    private static final String DRIVER_CLASS="com.microsoft.sqlserver.jdbc.SQLServerDriver";
    private static final String URL="jdbc:sqlserver://localhost:1433;databaseName=QDU";
    private static final String USERNAME = "sa";
    private static final String PASSWORD = "sa";

    /**
     * 获取数据库连接
     *
     * @return 一个数据库连接对象
     */
    public static Connection getConnection() {
        try {
            Class.forName(DRIVER_CLASS);
            return DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭数据库连接
     *
     * @param rs 结果集对象
     * @param ps 语句对象
     * @param con 连接对象
     */
    public static void close(ResultSet rs, PreparedStatement ps, Connection con) {
        try {
            if (null != rs) {
                rs.close();
            }
            if (null != ps) {
                ps.close();
            }
            if (null != con) {
                con.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

LoginServlet

package com.qdu.servlet;

import com.qdu.dao.StudentDao;
import com.qdu.pojo.Student;
import java.io.IOException;
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 javax.servlet.http.HttpSession;

@WebServlet("/ls")
public class LoginServlet extends HttpServlet {

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

        String rollno = req.getParameter("rollno");
        String pwd = req.getParameter("pwd");
        
        StudentDao dao=new StudentDao();
        Student stu=dao.findStudentByRollno(rollno);

        //如果stu不为null,说明学号正确,只需要再判断密码即可
        if (null!=stu&&pwd.equals(stu.getSpassword())) { 
            //会话技术就是为每一个浏览器用户分配一个HttpSession对象
            //用于在会话期间维护一些用户数据
            //getSession()获取和请求关联的会话对象,如果还没有会话对象,则创建一个新的会话对象
            
            //getSession(false)获取和请求关联的会话对象,如果还没有会话,返回null
            //HttpSession session=req.getSession(false);
            HttpSession session=req.getSession();
            //你可以将在会话期间共享的数据作为属性(attribute)放入会话对象
            //一个属性由一个属性名和一个属性值构成,后续使用的时候通过属性名获取属性值
            //属性名必须是字符串,属性的值可以是任何对象,如一个字符串,一个学生对象等
            session.setAttribute("student",stu);
            //session.setAttribute("number", 10);
            resp.sendRedirect("success.jsp");
        } else {
            resp.sendRedirect("fail.html");
        }
    }
}

Student.java

package com.qdu.pojo;

/**
 * 学生实体类,用于存储学生所有信息
 *
 * @author NIIT
 */
public class Student {

    private String srollno;
    private String sname;
    private String sgender;
    private String sbatch;
    private String spassword;

    public Student() {
    }

    public Student(String srollno, String sname, String spassword, String sgender, String sbatch) {
        this.srollno = srollno;
        this.sname = sname;
        this.sgender = sgender;
        this.sbatch = sbatch;
        this.spassword = spassword;
    }

    public String getSrollno() {
        return srollno;
    }

    public void setSrollno(String srollno) {
        this.srollno = srollno;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getSgender() {
        return sgender;
    }

    public void setSgender(String sgender) {
        this.sgender = sgender;
    }

    public String getSbatch() {
        return sbatch;
    }

    public void setSbatch(String sbatch) {
        this.sbatch = sbatch;
    }

    public String getSpassword() {
        return spassword;
    }

    public void setSpassword(String spassword) {
        this.spassword = spassword;
    }
}

StudentDao.java

package com.qdu.dao;

import com.qdu.pojo.Student;
import com.qdu.util.DatabaseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * Dao类-数据访问对象类,专门用于访问数据库中的表 <br>
 * StudentDao包含方法用于对StudentMark表执行增删改查, 这里只封装了一个方法用于查询
 *
 * @author Anna
 */
public class StudentDao {

    /**
     * 根据学号查询学生所有信息
     *
     * @param rollno 学生学号
     * @return 包含学生所有信息的学生对象
     */
    public Student findStudentByRollno(String rollno) {

        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = DatabaseUtil.getConnection();
            ps = con.prepareStatement("select * from student where Srollno=?");
            ps.setString(1, rollno);
            rs = ps.executeQuery();

            if (rs.next()) {
                return new Student(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseUtil.close(rs, ps, con);
        }
        return null;
    }
}

LogoutServlet

package com.qdu.servlet;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

@WebServlet("/los")
public class LogoutServlet extends HttpServlet {

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

        //getSession(false)获取已有的会话对象,如果还没有会话对象,则返回null
        HttpSession session = req.getSession(false);
        if (null != session) {//如果会话不为null
            session.invalidate(); //调用invalidate()使会话无效,也就是立刻结束会话
            resp.sendRedirect("index.html"); //退出登录后回到首页
            
            //session.setMaxInactiveInterval(10*60); 单位是秒
        }
    }
}

C02_D06_SessionExercise
在这里插入图片描述
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>天猫首页</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="images/shortcut.png" rel="shortcut icon" type="image/x-icon"/>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">

            <div class="top">
                <div class="top_left"><img src="images/tmall.png" alt="天猫logo"></div>
                <div class="top_right"><h1>欢迎来到天猫,理想生活上天猫......</h1></div>
            </div>

            <hr>

            <h3>最新活动</h3>
            <br>

            <ul>
                <!--可以通过url重写追加请求参数,体现是不同的产品-->
                <li><a href="ps?pid=P001">卫龙辣条,你值得拥有</a></li>
                <li><a href="ps?pid=P002">青岛大虾,不一样的大虾</a></li>
                <li><a href="ps?pid=P003">四级真题,600包过</a></li>
                <li><a href="ps?pid=P004">快乐肥宅水,你今天快乐了吗?</a></li>
            </ul>

            <br>
            <a href="cart.jsp">查看购物车</a>

        </div>
    </body>
</html>

style.css


.top{
    height: 120px;
}

.top_left{
   width: 20%;
   float:left;
}

.top_right{
   width: 80%;
   float:left;
}

.top_right h1{
    height: 100px;
    line-height: 100px;
    margin-left:50px;
    color: darkred;
}

.content{
    position: relative;
    padding-left: 300px;
    width: 700px;
    margin: 30px auto;
}

.pic{
    position: absolute;
    top: 20px;
    left: 0px;
    width: 250px;
    height: 250px;
}

.viewcart{
    position: fixed;
    top: 30px;
    right: 30px;
}

.title{
    color: brown;
    text-align: center;
}

form .form-control{
    width: 60px!important;
}

.cartProduct{
    position: relative;
}

.cartProduct img{
    position: absolute;
    top: 11px;
    left: 200px;
    border-radius: 100px;
    border: solid lightgray 1px;
}

ul{
    line-height: 30px;
}

ProductDao.java

package com.tianmao.dao;

import com.tianmao.util.DatabaseUtil;
import com.tianmao.entity.Product;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * Dao类-数据访问对象类,专门用于访问数据库中的表ProductDao包含方法用于对Product表执行增删改查
 * @author Anna
 */
public class ProductDao {

    /**
     * 查询所有产品的列表
     * @return 产品列表
     */
    public List<Product> getProductList() {

        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Product> productList=new ArrayList();

        try {
            con = DatabaseUtil.getConnection();
            ps = con.prepareStatement("select * from Product");
            rs = ps.executeQuery();

            while (rs.next()) {
                productList.add(new Product(rs.getString(1),rs.getString(2),rs.getFloat(3),rs.getString(4),rs.getInt(5)));
            } 
            return productList;
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            DatabaseUtil.close(rs,ps,con);
        }
        return null;
    }
    
    /**
     * 根据产品编号查询产品信息
     * @param productId 字符串表示的产品编号
     * @return 包含产品所有信息的一个Product对象,如果没有查询到该产品,则返回null
     */
    public Product findProductById(String productId) {

        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = DatabaseUtil.getConnection();
            ps = con.prepareStatement("select * from Product where productId=?");
            ps.setString(1, productId);
            rs = ps.executeQuery();

            if (rs.next()) {
                return new Product(rs.getString(1),rs.getString(2),rs.getFloat(3),rs.getString(4),rs.getInt(5));
            } 
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            DatabaseUtil.close(rs,ps,con);
        }
        return null;
    }
}

ProductServlet

package com.tianmao.servlet;

import com.tianmao.dao.ProductDao;
import com.tianmao.entity.Product;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 该Servlet处理根据产品编号查询产品的请求,然后将查询出来的产品信息交给productInfo.jsp显示
 *
 * @author Anna
 */
@WebServlet("/ps")
public class ProductServlet extends HttpServlet {

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

        //1. 获取请求参数
        String pid=req.getParameter("pid");
        
        //2. 执行业务逻辑,完成请求处理
        ProductDao dao=new ProductDao();
        Product pro=dao.findProductById(pid); //根据产品编号查询单个产品的所有信息
        
        //3. 将查询到的信息共享给productInfo.jsp页面显示
        //如果希望将一些信息共享到下个servlet或jsp,而不是通过会话共享
        //则可以考虑将信息作为属性添加到请求对象,然后转发请求
        //可以将产品对象作为一个属性放入请求对象,这里属性名是product
        req.setAttribute("product", pro);
        //将同一个请求对象和响应对象转发给productInfo.jsp
        //这样productInfo.jsp收到的请求是同一个请求,所以可以获取到共享的数据
        
        //forward转发
        req.getRequestDispatcher("/productInfo.jsp").forward(req, resp);
    }
}

productInfo.jsp


<%@page import="com.tianmao.entity.Product"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="images/shortcut.png" rel="shortcut icon" type="image/x-icon"/>
        <title>产品信息</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <h1 class="text-center text-primary">产品信息</h1>
        <hr>
        <br>
        
        <!--在此div中显示从数据库查询到的一个产品的所有信息-->
        
        <%
            //因为ps这个servlet转发了请求给productInfo.jsp
            //所以productInfo.jsp收到的请求就是ps收到的请求,两个处理的是同一个请求
            Product p=(Product)request.getAttribute("product");
        %>
        
        <div class="content">
            <br>
            <!--显示产品图片,图片在images文件夹中给出了,以产品的编号命名的图片-->
            <img src="images/<%=p.getProductId()%>.jpg" class="pic">  
            
            <h3>产品名称: <%=p.getProductName() %>  </h3>
            <p>产品单价: <%=p.getProductPrice()%>   </p>
            <p>包装单位: <%=p.getProductUnit()%>   </p>
            <p>剩余库存: <%=p.getProductQty()%>   </p>
            
            <!--提交请求给cs,添加产品到购物车 shopping cart-->
            <form action="cs" class="form-inline">
                <b>购买数量:</b>
                <input type="number" min="1" name="qty" value="1" class="form-control">
                <br><br>
                <!--在表单中,如果有些数据需要隐式地提交,则可以使用隐藏字段-->
                <input type="hidden" name="pid" value="<%=p.getProductId()%>">
                <!--为了简化程序,后续不再次查询数据库,我们考虑将产品的其他信息一起提交-->
                <input type="hidden" name="pname" value="<%=p.getProductName() %>">
                <input type="hidden" name="pprice" value="<%=p.getProductPrice() %>">
                <input type="hidden" name="punit" value="<%=p.getProductUnit() %>">
                
                <input type="submit" value="加入购物车" class="btn btn-sm btn-danger"> &nbsp;
                <input type="submit" value="立刻购买" class="btn btn-sm btn-warning">
            </form>
        </div>

        <br>
        <a href="cart.jsp" class="viewcart">查看购物车</a>

    </body>
</html>

CartServlet

package com.tianmao.servlet;

import com.tianmao.entity.Product;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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 javax.servlet.http.HttpSession;
import javax.swing.JButton;

/**
 * 点击“加入购物车”按钮,添加产品到购物车,该Servlet负责处理添加到购物车的请求
 *
 * @author Anna
 */
@WebServlet("/cs")
public class CartServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        //1. 获取请求参数
        String pid = req.getParameter("pid"); //Ctrl+Shift+上/下
        String pname = req.getParameter("pname");
        //byte,short,int,long,float,double,char,boolean
        //Byte,Short,Integer,Long,Float,Double,Character,Boolean
        float pprice = Float.parseFloat(req.getParameter("pprice"));
        String punit = req.getParameter("punit");
        int qty = Integer.parseInt(req.getParameter("qty"));

        //为了更方便的操作产品的5项信息,可考虑将其封装成一个产品对象
        //但是这里的数量表示的不是库存量,而是加入购物车的数量
        Product p = new Product(pid, pname, pprice, punit, qty);

        //可以考虑维护一个Product列表,用于存储购物车中所有产品的信息
        //添加一个产品到购物车,也就是添加一个产品对象到该列表中
        
        List<Product> list=null; //定义一个变量,表示购物车列表
        HttpSession session=req.getSession(); //获取会话对象
        
        //如果会话中已经有了cartList属性,说明不是第一次添加产品到购物车
        //否则说明是第一次添加产品到购物车
        if(null!=session.getAttribute("cartList")){
            //如果已经有列表,获取该购物车列表,赋值给变量list
            //因为实际放入的是一个List<Product>类型,所以可以强制转换类型 
            list=(List<Product>)session.getAttribute("cartList");
            list.add(p); //添加本次的产品到购物车列表
        }else{ //第一次添加产品到购物车
            list=new ArrayList(); //创建购物车列表
            list.add(p); //添加第一个产品到购物车列表
            //为了让购物车列表在会话期间可访问,可将购物车列表添加到会话中
            session.setAttribute("cartList",list); //将购物车列表作为一个属性添加到会话对象
        }
        
        //因为列表是在会话中,不是在请求对象中,所以直接重定向到cart.jsp页面显示购物车列表即可
        resp.sendRedirect("cart.jsp");
    }
}

cart.jsp

<%@page import="java.util.List"%>
<%@page import="com.tianmao.entity.Product"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="images/shortcut.png" rel="shortcut icon" type="image/x-icon"/>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
        <title>购物车信息</title>
    </head>
    <body>

        <div class="container">

            <h1 class="text-center text-danger">购物车信息</h1>


            <!--这里给出了购物车中一个产品的显示格式-->
            <%
                //根据属性名cartList获取属性值,值是一个List<Product>对象
                List<Product> clist=(List)session.getAttribute("cartList");
                if(null==clist){
                    out.println("<br><h1>尚未添加任何产品到购物车!!!</h1>");
                    return; //如果没有产品,无需遍历,直接返回即可,这样后面的代码都不会执行
                }
                //如果购物车中有产品,则执行后续代码,遍历列表
                float total=0; //定义一个变量,用于存储总计金额
                for(Product p:clist){ //对于集合clist中的每个产品
                    total+=p.getProductPrice() * p.getProductQty(); //总计金额每次在原来的基础上加上当前产品的小计金额
            %>
            <div class="cartProduct">
                <img src="images/<%=p.getProductId()%>.jpg" width="120" height="120"> 
                <hr>
                产品名称:<%=p.getProductName() %>
                <br>产品单价:<%=p.getProductPrice() %>
                <br>包装单位:<%=p.getProductUnit() %>
                <br>购买数量:<%=p.getProductQty() %>
                <br><b class="text-primary">小计金额:<%=p.getProductPrice() * p.getProductQty()%></b>
            </div>
            <% } %>
            <hr>
            <h3 class="text-danger">总计金额:<%=total%></h3>

        </div>
    </body>
</html>

C02_D05_Listeners
在这里插入图片描述
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <title>Servlet相关的监听器</title>
    </head>
    <body class="bg-danger">

        <div class="container">

            <h1 class="text-center text-primary">Servlet相关的监听器</h1>
            <hr>

            <h2>(1). 会话(HttpSession)相关监听器</h2>
            <br>

            <a href="second.jsp" class="text-danger">* 跳转到页面2</a>
            <br><br>
            <a href="s1">* 开始会话</a>
            <br><br>
            <a href="s2">* 结束会话</a>
            <br><br>
            <a href="s3">* 操作会话中的属性</a>

            <hr>

            <h2>(2). 上下文(ServletContext)相关监听器</h2>
            <br>

            <a href="s4">* 操作上下文中的属性</a>

            <hr>
            
            <h2>(3). 请求(ServletRequest)相关监听器</h2>
            <br>


            <a href="s5">* 请求Servlet5</a>
            <br><br>
            <a href="s6">* 操作请求对象中的属性</a>
            
            <hr>
        </div>

    </body>
</html>


second.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <title>页面2</title>
    </head>
    <body>
        
        <div class="container bg-success">
            
            <h1>页面2</h1>
            <hr>
            <br>
            
            <%=session.getAttribute("name") %>
            
            <br>
            <br>
            <br>
        </div>
        
    </body>
</html>

在这里插入图片描述
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <listener>
        <description>监听会话的创建和摧毁</description>
        <listener-class>com.qdu.listener.MySessionListener</listener-class>
    </listener>
    <listener>
        <description>监听会话对象中属性的变化</description>
        <listener-class>com.qdu.listener.MySessionAttributeListener</listener-class>
    </listener>
    <listener>
        <description>监听上下文对象的创建和摧毁</description>
        <listener-class>com.qdu.listener.MyContextListener</listener-class>
    </listener>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

在这里插入图片描述
Servlet1

package com.qdu.servlet;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

@WebServlet("/s1")
public class Servlet1 extends HttpServlet {

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

        HttpSession session=req.getSession();
        session.setAttribute("name", "Anna");
        
        resp.sendRedirect("index.html");
    }
}

MySessionListener

package com.qdu.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * 会话监听器(HttpSessionListener)
 * <br>监听会话对象的创建和摧毁事件
 *
 * @author Anna
 */
//创建监听器(listener),绝大部分监听器都是接口
//1. 如果想创建对应的监听器类,实现对应的监听器接口即可
//2. 在web.xml中或使用@WebListener注册监听器
//@WebListener
public class MySessionListener implements HttpSessionListener{

    //该方法响应会话对象被创建而调用,并且自动传入一个参数,参数是一个事件对象
    //包含事件发生的信息,如创建的会话
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("有新会话被创建,会话编号:"+se.getSession().getId());
    }

    //该方法响应会话对象被摧毁而调用,并且自动传入一个参数,参数是一个事件对象
    //包含事件发生的信息,如创建的会话
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("有会话被摧毁,会话编号:"+se.getSession().getId());
    }
}

MySessionAttributeListener

package com.qdu.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * 创建会话属性监听器(HttpSessionAttributeListener)
 * <br>监听会话对象中属性的添加、修改和删除事件
 *
 * @author Anna
 */
public class MySessionAttributeListener implements HttpSessionAttributeListener{

    //当监听到会话中添加了新属性后,attributeAdded()被调用
    //并自动传入一个事件对象,包含事件信息
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        //通过事件对象可以获取添加的属性的信息,或者获取会话对象进行一些操作
        //getName()获取添加的属性的名称,getValue()获取添加的属性的值
        System.out.println("会话中添加了新属性,属性:"+event.getName()+"-"+event.getValue());
    }

    //当监听到会话中删除了属性后,attributeRemoved()被调用
    //并自动传入一个事件对象,包含事件信息
    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
        System.out.println("会话中删除了属性,属性:"+event.getName()+"-"+event.getValue());
    }

    //当监听到会话中修改了一个属性后,attributeReplaced()被调用
    //并自动传入一个事件对象,包含事件信息
    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
        System.out.println("会话中修改了属性,属性:"+event.getName()+"-"+event.getValue());
    }

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Servlet4


package com.qdu.servlet;

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

@WebServlet("/s4")
public class Servlet4 extends HttpServlet {

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

        //在Servlet中获取程序的上下文对象
        //在Servlet中可调用继承的getServletContext()方法获取上下文对象
        ServletContext ctx=getServletContext();
        //放入上下文对象的属性是整个程序中可用
        ctx.setAttribute("count", 1000); //第一次设置一个属性是添加属性
        ctx.setAttribute("count", 2000); //第二次设置已有的属性是修改属性
        ctx.removeAttribute("count"); //removeAttribute()用于删除一个属性ctx.setAttribute("count", 1000);
        resp.sendRedirect("index.html");
    }
}

在这里插入图片描述
MyContextListener

package com.qdu.listener;

//ServletContext Servlet上下文

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

//一个程序有且仅有一个上下文对象,用于在整个程序期间使用,可用于在程序中共享数据
//你觉得程序的上下文对象什么时候被创建,什么时候被摧毁?
/**
 * 创建上下文监听器(ServletContextListener)
 * <br>监听器上下文对象的初始化和摧毁事件
 * 
 * @author Anna
 */
//程序上下文对象在程序启动的时候就会被创建和初始化
//一般是程序停止或关闭服务器才会导致上下文对象被摧毁
//@WebListener
public class MyContextListener implements ServletContextListener{

    //当监听器监听到上下文对象被初始化,初始化也就是意味着对象被创建了
    //并且自动传入一个事件对象,包含事件信息,可通过该对象获取上下文对象进行操作
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //一般如果程序启动就需要加载一些数据到上下文对象中,方便程序后面使用
        //一般需要在该方法中写代码
        System.out.println("上下文对象被创建!");
    }

    //当监听器到上下文对象被摧毁,该方法被调用
    //并且自动传入一个事件对象,包含事件信息,可通过该对象获取上下文对象进行操作
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("上下文对象被摧毁!");
    }
}

MyContextAttributeListener

package com.qdu.listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

/**
 * 创建上下文属性监听器(ServletContextAttributeListener)
 * <br>监听上下文对象中属性的添加、修改和删除事件
 * 
 * @author Anna
 */
@WebListener //和在web.xml中使用listener标记注册监听器等效,使用其中一个方式即可
public class MyContextAttributeListener implements ServletContextAttributeListener{
    @Override
    public void attributeAdded(ServletContextAttributeEvent event) {
        System.out.println("上下文对象中添加了新属性,属性:"+event.getName()+"-"+event.getValue());
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent event) {
        System.out.println("上下文对象中删除了属性,属性:"+event.getName()+"-"+event.getValue());
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent event) {
        System.out.println("上下文对象中修改了属性,属性:"+event.getName()+"-"+event.getValue());
    }
}

Servlet5

package com.qdu.servlet;

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

@WebServlet("/s5")
public class Servlet5 extends HttpServlet {

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

        PrintWriter out=resp.getWriter();
        out.println("<h1>Hi, This is Servlet5!</h1>");
    }
}

在这里插入图片描述
MyRequestListener

package com.qdu.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

/**
 * 创建请求监听器(ServletRequestListener)
 * <br>监听器请求对象的初始化和摧毁事件
 *
 * @author Anna
 */
//@WebListener
public class MyRequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
        System.out.println("摧毁了请求对象,请求路径为:" + req.getRequestURI());
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
        System.out.println("创建了新的请求对象,请求路径为:" + req.getRequestURI());
    }

}

MyRequestAttributeListener

package com.qdu.listener;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;

/**
 * 创建请求属性监听器(ServletRequestAttributeListener)
 * <br>监听请求对象中属性的添加、修改和删除事件
 *
 * @author Anna
 */
public class MyRequestAttributeListener implements ServletRequestAttributeListener {

    @Override
    public void attributeAdded(ServletRequestAttributeEvent event) {
        System.out.println("请求对象中添加了新属性:" + event.getName() + "-" + event.getValue());
    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent event) {
        System.out.println("请求对象中删除了属性:" + event.getName() + "-" + event.getValue());
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent event) {
        System.out.println("请求对象中修改了属性:" + event.getName() + "-" + event.getValue());
    }
}

Servlet6

package com.qdu.servlet;

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

@WebServlet("/s6")
public class Servlet6 extends HttpServlet {

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

        req.setAttribute("name", "小强");
        req.setAttribute("name", "小红");
        req.removeAttribute("name");
        resp.sendRedirect("index.html");
    }
}

在这里插入图片描述
在这里插入图片描述
输入5 和 2
在这里插入图片描述
被除数是0时
在这里插入图片描述
输入字母时

在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>了解状态码</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">

            <br>
            <h1 class="text-center text-danger">了解状态码</h1>

            <p>* 地址栏Url故意打错或除数输入0或字母查看状态码,该程序要求输入的是整数</p>
            <p>* 该程序主要是认识和了解状态码,所以并没有让你们去写任何代码</p>
            <hr>
            <br>

            <form action="cs" class="form-inline">
                <table>
                    <tr>
                        <td colspan="2">
                            <h3 class="text-center">计算器</h3>
                        </td>
                    </tr>
                    <tr>
                        <td>输入被除数:</td>
                        <td><input type="text" name="num1" class="form-control"></td> 
                    </tr>
                    <tr>
                        <td>输入除数:</td>
                        <td><input type="text" name="num2"  class="form-control"></td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            <input type="submit" class="btn btn-sm btn-danger" value="计算">
                        </td>
                    </tr>
                </table>
            </form>
        </div>
    </body>
</html>

CalculateServlet

package com.qdu.servlet;

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

@WebServlet("/cs")
public class CalculateServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        int a=Integer.parseInt(request.getParameter("num1"));
        int b=Integer.parseInt(request.getParameter("num2"));
        
        int result=a/b;
        
        response.setContentType("text/html;charset=utf-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<br><h1>计算结果:" + result + "</h1>");
        }
    }
}

C02_D08_HandleError1
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>处理错误</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
    </head>
    <body>

        <div class="container">

            <h1 class="text-center text-danger">处理错误-自定义错误页面</h1>
            <hr>
            <br>

            <ul>
                <li><a href="download.html">四六级真题下载园地</a></li>
                <li><a href="cet4Answer.jsp">2017年12月四级答案</a></li>
                <li><a href="takeCet4Servlet">四级模拟测试</a></li>
                <li><a href="secret.html">秘诀-如何取得四级600分</a></li>
            </ul>
            
            <br>
            <br>

            <a href="images/longmao1.gif" title="查看原图">
                <img src="images/longmao1.gif" alt="行走的龙猫" width="250" height="182">
            </a>

            <a href="images/longmao.gif" title="查看原图">
                <img src="images/longmao2.gif" alt="行走的龙猫" width="182" height="182">
            </a>

        </div>

    </body>
</html>

在这里插入图片描述
在这里插入图片描述
目录里并没有这些资源,访问
在这里插入图片描述
在这里插入图片描述
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <!--error-page用于配置错误页面-->
    <error-page>
        <!--error-code指定针对的错误代码-->
        <error-code>404</error-code>
        <!--location:位置,用于指定错误页面的位置,也就是路径-->
        <location>/error_page.jsp</location>
    </error-page>
    
</web-app>

error_page.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>这个.. 页面没有找到!!!</title>
        
        <style type="text/css">
            body{ margin:0; padding:0; font-family: 微软雅黑; }
            div#mother{ margin:0 auto; width:943px; height:572px; position:relative; }
            div#errorBox{ background: url(${pageContext.request.contextPath}/images/longmao3.gif) no-repeat center left; width:943px; height:572px; margin:auto; }
            div#errorText{ color:#39351e; padding:185px 0 0 456px }
            div#errorText p{ width:303px; font-size:14px; line-height:26px; }
            div.link{ height:50px; width:145px; float:left;background-color:red;color: black; }
            div#home{ margin:0 0 0 444px;}
            div#contact{ margin:0 0 0 25px;}
            h1{ font-size:40px; margin-bottom:35px; }
        </style>

    </head>
    <body>
        <div id="mother">
            <div id="errorBox">
                <div id="errorText">
                    <h1>Sorry..页面没有找到!</h1>
                    <p>似乎你所寻找的网页已移动或丢失了。</p>
                    <p>请不要担心,这没事。</p>
                    <p>如果该资源对你很重要,请与<a href="mailto: anna@163.com">管理员</a>联系。</p>
                    <p>火星不太安全,我可以免费送你回地球!</p>
                </div>
            </div>
        </div>
    </body>
</html>

C02_D09_HandleError2
在这里插入图片描述

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>处理错误和异常</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>

        <div class="container">

            <br>
            <h1 class="text-center text-danger">处理错误和异常</h1>

            <p>* 地址栏Url故意输入0或字母查看状态码,该程序要求输入的是整数</p>
            <hr>
            <br>

            <form action="cs" class="form-inline">
                <table>
                    <tr>
                        <td colspan="2">
                            <h3 class="text-center">计算器</h3>
                        </td>
                    </tr>
                    <tr>
                        <td>输入被除数:</td>
                        <td><input type="text" name="num1" value="100" class="form-control"></td> 
                    </tr>
                    <tr>
                        <td>输入除数:</td>
                        <td><input type="text" name="num2" value="0"  class="form-control"></td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            <input type="submit" class="btn btn-sm btn-danger" value="计算">
                        </td>
                    </tr>
                </table>
            </form>
        </div>
    </body>
</html>

在这里插入图片描述
style.css

h1{
    text-align: center;
    color: brown;
}


table td{
    padding: 5px;
}

CalculateServlet

package com.qdu.servlet;

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

@WebServlet("/cs")
public class CalculateServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        int num1 = Integer.parseInt(request.getParameter("num1"));
        int num2 = Integer.parseInt(request.getParameter("num2"));

        int result = 0;

        result = num1 / num2;

        response.setContentType("text/html;charset=utf-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<br><h1>计算结果:" + result + "</h1>");
        }
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <!--可以针对错误代码配置错误页面-->
    <!--    
    <error-page>
        <error-code>500</error-code>
        <location>/error_500.html</location>
    </error-page>
    -->
    <!--也可针对异常类型配置错误页面-->
    <!--exception-type标记指定针对的异常类型-->
    <!--    
    <error-page>
        <exception-type>java.lang.ArithmeticException</exception-type>
        <location>/error.jsp</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.NumberFormatException</exception-type>
        <location>/error.jsp</location>
    </error-page>
    -->
    <!--所有的异常类都直接或间接实现了Throwable接口,所以java.lang.Throwable表示所有异常-->
    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/error.jsp</location>
    </error-page>
    
</web-app>

error.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>异常错误页面</title>
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
    </head>
    <body class="bg-warning">

        <div class="container">
            <br>
            <h1 class="text-center text-danger">异常错误页面</h1>
            <hr>

            <!--如果发生异常,转到指定的错误页面(错误页面可以是一个页面或一个servlet),
                异常信息会传送到该页面,所以可以获取错误异常信息
                服务器通过请求对象的setAttribute()方法将异常信息放入到请求对象
                所以在错误页面,可通过请求的getAttribute()方法获取异常信息
            -->
            <%
                out.println("<br>状态代码: " + request.getAttribute("javax.servlet.error.status_code"));
                out.println("<br>异常消息: " + request.getAttribute("javax.servlet.error.message"));
                out.println("<br>异常类型: " + request.getAttribute("javax.servlet.error.exception_type")); 

                //获取程序的上下文对象吧
                ServletContext ctx = getServletContext();
                //也可根据需求自己写入信息到日志
                ctx.log("异常消息:"+request.getAttribute("javax.servlet.error.message"));
            %>
            
        </div>
    </body>
</html>

error_500.html

<!DOCTYPE html>
<html>
    <head>
        <title>状态代码500-错误页面</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <h1 style="color: red;text-align: center;">500-服务器端出错,<a href="#">发送</a>信息给管理员!</h1>
    </body>
</html>

C02_D10_setStatus
在这里插入图片描述

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>百搜一下,你就知道</title>
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>
        
        <h1>百搜-搜天下</h1>
        <form>
            <input type="text">
            <input type="submit" value="百搜一下">
        </form>
        
        <%
            //特殊的情况下,需要自行决定发送给客户端的状态码
            //可调用以下两个方法
            //sendError()方法  用于发送4或5开头的错误代码
            //setStatus()方法  用于发送非错误状态代码
            
            //响应报头location用于指定一个目标url
            response.setHeader("location","https://www.baidu.com");
            //response.setStatus(301);
            //永久地 permanently 301永久重定向,说明永久定向导新的地址
            //临时地 temporarily 302临时重定向,说明临时定向到新的地址
            //除了用对应的数字状态码,也可使用HttpServletResponse接口中的各种常量名
            response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
            
            //www.tianmao.com
            //www.tianmaomao.com
            
            //可以只指定发送的错误代码
            //response.sendError(410);
            //也可同时指定发送的错误代码和一个消息
            //response.sendError(410, "该资源已经永久删除了!");
        %>
        
    </body>
</html>

C02_D11_sendError在这里插入图片描述

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>百搜一下,你就知道</title>
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body> 
        <h1>百搜搜-搜天下</h1>
        <form>
            <input type="text">
            <input type="submit" value="百搜一下">
        </form>
        <%
            //可以只指定发送的错误代码
            //response.sendError(410);
            //也可同时指定发送的错误代码和一个消息
            //response.sendError(410, "该资源已经永久删除了!");
        %>
    </body>
</html>

在这里插入图片描述
style.css

body{font-family:微软雅黑;}
h1{text-align: center; color:darkcyan;margin-top: 100px;}
form{width: 650px; margin: 50px auto;}
input[type="text"]{width: 500px; height: 40px; outline: none; border: solid 1px lightblue; padding: 0 10px; border-radius: 5px;}
input[type="submit"]{width: 100px; height: 42px;border-radius: 5px; background-color: chocolate; border: none;
color: white; font-size: 18px;}
input[type="submit"]:hover{cursor: pointer; background-color: crimson;}

在这里插入图片描述
C02_D12_RequestDispatch_ResponseRedirect
在这里插入图片描述
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>请求转发和响应重定向</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/bootstrap.min.css"/>
    </head>
    <body>

        <div class="container">

            <br>
            <h1 class="text-center text-danger">请求转发和响应重定向</h1>
            <hr>
            <br>

            <ul>
                <li><a href="firstServlet?flag=1">1. 响应重定向-sendRedirect</a></li>
                <li><a href="firstServlet?flag=2">2. 请求转发-forward</a></li>
                <li><a href="firstServlet?flag=3">3. 请求转发-include</a></li>
            </ul>

        </div>
    </body>
</html>

second.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>页面second</title>
    </head>
    <body>
        
        <div style="color:red;">
            <p>****************************************************************</p>
            <h1>页面second的内容</h1>
            <!--获取一下请求参数flag的值,看看是不是同一个请求对象-->
            <p>请求参数flag: <%=request.getParameter("flag")%> </p>
            <p>请求中的属性: <%=request.getAttribute("number")%> </p>
            <p>****************************************************************</p>
        </div>
        
    </body>
</html>

1
在这里插入图片描述
FirstServlet


package com.qdu.servlet;

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

@WebServlet("/firstServlet")
public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out=resp.getWriter();
        out.println("<br><h1>这是FirstSevlet输出的内容-开始</h1>");
        
        //获取请求参数flag的值并将其转换成整数
        int flag=Integer.parseInt(req.getParameter("flag"));
        
        switch(flag){
            case 1: //实现重定向
                //1)最后显示重定向后资源的内容
                //2) 地址栏显示重定向后的资源的url
                //3) 整个过程中产生了2个请求,重定向是发起一个新请求,请求重定向后的资源(页面或servlet等)
                resp.sendRedirect("second.jsp"); //重定向到second.jsp
                break;
            case 2: //调用forward()方法转发请求
                //1)最后显示转发后的资源的内容
                //2) 地址栏显示转发向前的资源的url
                //3) 整个过程中产生了1个请求
                //request请求 dispatch派遣、派发 forward转发
                //请求对象的getRequestDispatcher()用于获取一个可以派发/转发请求的请求派发器对象
                //一个RequestDispatcher对象是可以用于派发请求的对象,需要指定转发目标,也就是请求转发给谁
                //目标的url可以用相对路径或类似绝对路径(/开头)
                //RequestDispatcher rd=req.getRequestDispatcher("/second.jsp");
                //调用forward()方法转发请求即可
                //该方法接受两个参数,表示要转发的请求对象和响应对象
                //这样导致转发请求的组件(servlet或jsp)和目标组件(servlet或jsp)收到的请求对象和响应对象都是同一个
                //rd.forward(req, resp);
                //也可获取了请求派遣器对象后直接操作,而不用变量接收请求派遣器对象
                //如果产生了一些数据,需要共享给下个组件(servlet或jsp),一般选择转发请求
                //可以将数据作为属性放入请求对象,然后转发请求
                req.setAttribute("number",666666);
                req.getRequestDispatcher("/second.jsp").forward(req, resp);
                break;
            case 3: //调用include()方法转发请求,将转发后的组件(second.jsp)的内容包含到当前组件(FirstServlet)中显示
                //A->B forward转发  B
                //A->B include转发  A+B
                //1)最后显示转发前+后的资源的内容
                //2) 地址栏显示转发向前的资源的url
                //3) 整个过程中产生了1个请求
                req.getRequestDispatcher("/second.jsp").include(req, resp);
                break;
        }
        
        out.println("<h1>这是FirstSevlet输出的内容-结束</h1>");
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
C02_D13_ThreadModel1
在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Servlet线程模型</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body style="background-color: antiquewhite;">
        
        <h1>Servlet线程模型-多线程模型和单线程模型</h1>
        <hr>
        <br>
        <a class="sa" href="servletA">请求ServletA-抽小奖</a>
        <a class="sb" href="servletB">请求ServletB-抽大奖</a>
        
    </body>
</html>

style.css

h1{
    color: darksalmon;
    text-align: center;
}

a{
    display: block;
    width: 200px;
    height: 40px;
    line-height: 40px;
    margin: 30px auto;
    background-color: darkcyan;
    color: white;
    text-align: center;
    text-decoration: none;
}

a.sb{
    background-color: red;
}

a:hover{
    text-decoration: underline;
    background-color: brown;
}


ServletA

package com.qdu.servlet;

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

//默认一个Servlet使用多线程模型处理请求, 单实例,多线程
@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    
    //一旦一个Servlet被实例化之后,接着会被初始化,所以初始化了,说明已经实例化
    //init()
    //service()->doGet()/doPost()
    //destroy()
    //所以可以重写init()方法看看实例化几次
    @Override
    public void init() throws ServletException {
        System.out.println("ServletA被实例化!!!");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Random rand = new Random();
        int money = rand.nextInt(10001) + 10000;

        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {

            out.println("<br><h1 style='text-align: center;'>ServletA</h1>");
            out.println("<hr><br><br>");
            if (money % 3 == 0) {
                out.println("<h1 style='text-align: center; color: red;'>恭喜您中得" + money + "元,随便花!</h1>");
            } else {
                out.println("<h1 style='text-align: center; color: black;'>很遗憾,您未中奖,还是好好学习吧!</h1>");
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述
ServletB

package com.qdu.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.SingleThreadModel;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//单线程模型: 多实例,多线程,需要实现SingleThreadModel接口,就可以应用单线程模型
@WebServlet("/servletB")
public class ServletB extends HttpServlet implements SingleThreadModel{

    @Override
    public void init() throws ServletException {
        System.out.println("ServletB被实例化.............");
    }

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

        Random rand = new Random();
        int money = rand.nextInt(1000001) + 1;
        
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {

            out.println("<br><h1 style='text-align: center;'>ServletB</h1>");
            out.println("<hr><br><br>");
            if (money % 7 == 0) {
                out.println("<h1 style='text-align: center; color: red;'>恭喜您中得" + money + "元,随便花!</h1>");
            } else {
                out.println("<h1 style='text-align: center; color: black;'>很遗憾,您未中奖,革命尚未成功,同志仍需努力啊!</h1>");
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述
C02_D14_ThreadModel2_Synchronization
在这里插入图片描述
在这里插入图片描述
index.html


<html>
    <head>
        <title>Servlet线程模型-同步化</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/style.css"/>
    </head>
    <body>
        
        <br>
        <h1>Servlet线程模型-同步化(Synchronization)</h1>
        <hr>
        <br>
        
        <!--withdraw 取款-->
        <!--deposit  存款-->
        
        <form action="ws">
            <label for="un">取款人:</label>
            <input id="un" type="text" name="username" placeholder="在此输入取款人姓名">
            <br><br>
            <label for="acc">取自账户:</label>
            <input id="acc" type="text" disabled value="621226 3803001183734">
            <br><br>
            <label for="accName">账户户名:</label>
            <input id="accName" type="text" disabled value="李凡凡">
            <br><br>
            <input type="submit" value="取款100块">
        </form>
        
    </body>
</html>

style.css

h1{
    color: darksalmon;
    text-align: center;
}

label{
    width: 90px;
    display: inline-block;
}

input[type="text"]{
    padding: 5px 10px;
    border:solid 1px lightblue;
    outline: none;
    border-radius: 5px;
}

input[type="submit"]{
    width: 290px;
    height: 40px;
    line-height: 40px;
    background-color: darkcyan;
    color: white;
    text-align: center;
    border:none;
    border-radius: 5px;
}

input[type="submit"]:hover{
    background-color: brown;
    cursor: pointer;
}

Account

package com.qdu.entity;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 银行账户类
 *
 * @author NIIT
 */
public class Account {

    String name; //账户持有人姓名
    int balance; //余额

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }

    /**
     * 传入取款人姓名,从一个账户取款100块
     *
     * @param who 取款人的姓名
     */
    //withdraw 取款 
    //deposit 存款
    //synchronized用于同步化一个方法,同步化的方法同一时刻只能由一个线程访问
    public synchronized void withdraw100(String who) {
        try {
            System.out.println(who + "取款前余额:" + balance);
            balance -= 100; //账户余额减少100
            Thread.sleep(1000); //休眠1s
            System.out.println(who + "取款后余额:" + balance);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

WithdrawServlet

package com.qdu.servlet;

import com.qdu.entity.Account;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/ws")
public class WithdrawServlet extends HttpServlet {

    Account account = new Account("李凡凡", 2000);
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String name = request.getParameter("username");
        //取款100块
        account.withdraw100(name);

        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<h1>" + name + "同志取款100成功!</h1>");
        }
    }
}

C02_D15_UseFilter1
在这里插入图片描述
index.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>登录页面</title>
        <link rel="stylesheet" href="css/login.css">
    </head>
    
    <body>
        
        <br>
        <br>
        <div  id="container">
            <br>
            <form method="post" action="ls.do">
                <table>
                    <caption>用户登录</caption>
                    <tr>
                        <td>账户:</td>
                        <td><input name="username" type="text" value="李凡凡"></td>
                    </tr>
                    <tr>
                        <td>密码:</td>
                        <td><input name="password" type="password" value="1234"></td>
                    </tr>
                    <tr class="foot">
                        <td colspan="2">
                            <input type="submit" value="登录">
                            <a href="register.html">注册</a>
                        </td>
                    </tr>
                </table>
            </form>
        </div>
        
    </body>
</html>

在这里插入图片描述
在这里插入图片描述
LoginServlet

package com.qdu.servlet;

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

@WebServlet("/ls.do")
public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        
        //可以修改请求的编码,但是一定要在获取请求参数前修改编码
        //这样可以解决中文参数乱码问题,但是这里的方式只适用于post请求
        //req.setCharacterEncoding("utf-8"); //该程序使用过滤器实现修改请求编码,所以这里不用了
        
        String uname = req.getParameter("username");
        String pwd = req.getParameter("password");

        resp.setContentType("text/html;charset=utf-8");
        try (PrintWriter out = resp.getWriter()) {
            out.println("<h1>登录信息</h1>");
            out.println("<hr>");
            out.println("<br>账号:" + uname);
            out.println("<br><br>密码:" + pwd);
        }
    }
}

register.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>注册页面</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/register.css">
    </head>

    <body>
        
        <div class="container">
            
            <h1 class="text-primary text-center">学生注册</h1>
            <hr>
            
            <form method="post" action="rs.do" class="form-inline">
                <table>
                    <tr>
                        <td><label for="srollno">学号:</label></td>
                        <td><input name="srollno" class="form-control" type="text" id="srollno" value="2017209999"></td>
                    </tr>
                    <tr>
                        <td><label for="spwd">密码:</label></td>
                        <td><input name="spwd"  class="form-control" type="password" id="spwd" value="666666"></td>
                    </tr>
                    <tr>
                        <td><label for="sname">姓名:</label></td>
                        <td><input name="sname"  class="form-control" type="text" id="sname" value="李凡凡"></td>
                    </tr>
                    <tr>
                        <td><label for="sgender">性别:</label></td>
                        <td>
                            <select name="sgender" id="sgender"  class="form-control">
                                <option value="男">男</option>
                                <option value="女">女</option>
                            </select>
                        </td>
                    </tr>
                    <tr>
                        <td><label for="sbatch">班级:</label></td>
                        <td>
                            <select name="sbatch" id="sbatch"  class="form-control">
                                <option value="17软件(Java)03">17软件(Java)03</option>
                                <option value="17软件(Java)04">17软件(Java)04</option>
                                <option value="17软件(Java)06">17软件(Java)06</option>
                            </select>
                        </td>
                    </tr>
                    <tr class="foot">
                        <td colspan="2" class="text-center">
                            <input type="submit" value="注册" class="btn btn-sm btn-primary">
                        </td>
                    </tr>
                </table>
            </form>
        </div>
    </body>
</html>

在这里插入图片描述
在这里插入图片描述

package com.qdu.servlet;

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

@WebServlet("/rs.do")
public class RegisterServlet extends HttpServlet {

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

        String srollno = req.getParameter("srollno");
        String spwd = req.getParameter("spwd");
        String sname = req.getParameter("sname");
        String sgender = req.getParameter("sgender");
        String sbatch = req.getParameter("sbatch");
        
        resp.setContentType("text/html;charset=utf-8");
        try (PrintWriter out = resp.getWriter()) {
            out.println("<h1>注册信息</h1>");
            out.println("<hr>");
            out.println("<br>学号:"+srollno);
            out.println("<br><br>密码:"+spwd);
            out.println("<br><br>姓名:"+sname);
            out.println("<br><br>性别:"+sgender);
            out.println("<br><br>班级:"+sbatch);
        }
    }
}

EncodingFilter

package com.qdu.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 创建一个过滤器,用于拦截包含中文参数的post请求,修改请求编码,然后放行请求去访问实际资源
 * <br>创建过滤器的步骤
 * <br>1. 实现Filter接口,创建过滤器类
 * <br>2. 在web.xml中或使用@WebFilter注解注册过滤器才能使用过滤器
 *
 * @author NIIT
 */
//过滤器在程序启动的时候就会实例化,可以看下init()方法中的代码在程序启动的时候就会输出
public class EncodingFilter implements Filter {

    //init()方法在过滤器实例化后被调用,该方法被调用说明过滤器被实例化了
    //如果在过滤器拦截请求之前需要做一些初始工作,在此方法中编写代码
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init被调用了!!!......;.");
    }

    //过滤器应该执行的逻辑代码在此方法编写,也就是过滤器需要实现的功能
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //该方法接收三个参数
        //1. 表示拦截的请求对象
        //2. 表示拦截的响应对象
        //3. 一个FilterChain对象,表示过滤器链,可用于操作过滤器链上的过滤器
        //可以在控制台观察下面这行代码的输出判断过滤器的doFitler()方法什么时候被调用
        System.out.println("doFitler被调用...............");
        request.setCharacterEncoding("utf-8"); //修改请求编码
        //FilterChain接口的doFilter()方法的调用导致过滤器链上的下一个过滤器被调用
        //如果没有下一个过滤器,则导致过滤器链上终端的实际资被调用,也就是请求到达实际资源
        chain.doFilter(request, response); //放行请求去访问资源
    }
    //destroy()方法在一个过滤器实例被摧毁前调用,用于释放资源
    
    @Override
    public void destroy() {
        System.out.println("destroy被调用!!!........");
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <!--filter标记用于指定一个过滤器的名称、描述和类名-->
    <filter>
        <description>拦截包含中文参数的post请求,修正请求编码</description>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.qdu.filter.EncodingFilter</filter-class>
    </filter>
    <!--如果想拦截某种类型的请求,可以考虑请求路径具有相同的后缀(如*.do)或前缀(如/post/*)-->
    <!--filter-mapping标记指定一个过滤器的映射,也就是过滤器过滤什么样的请求,也就是拦截什么样的请求-->
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--<url-pattern>/ls</url-pattern>-->
        <!--<url-pattern>/rs</url-pattern>-->
        <url-pattern>*.do</url-pattern>
        <!--<url-pattern>/post/*</url-pattern>-->
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
</web-app>

login.css

@charset "utf-8";

#container{
	width: 280px; 
	margin: 50px auto 0 auto;
        background-color:#CC0; 
}

table{
	width:100%;
	border-spacing: 10px;
}

table caption{
	background-color:#C60;
        padding: 10px 0 10px 0;
	font-size: 30px;
	font-weight: bold;	
        color: white;
}

input[type="text"],input[type="password"],select{
    padding:5px 10px;
    border: none;
    outline:none;
    border-radius: 5px;
}

input[type="submit"],a{
    width: 70px;
    height: 30px;
    line-height: 30px;
    background-color: darkcyan;
    color: white;
    text-align: center;
    border:none;
    border-radius: 5px;
}

a{
    display: inline-block;
    text-decoration: none;
}

input[type="submit"]:hover{
    background-color: brown;
    cursor: pointer;
}

a{
    background-color: darkorange;
}

a:hover{
    text-decoration: underline;
    background-color: brown;
}

table tr.foot{
	text-align: center;
}


register.css


    @charset "utf-8";

#container{
    width: 320px; 
    margin: 50px auto 0 auto;	
    background-color:#CC0; 
}

table{
    border-spacing: 20px;
    width:270px;
    margin: 30px auto;
}

table td{
    padding: 6px;
}

select{
    width: 196px!important;
}

.gender{
    margin-left: 5px;
    margin-right: 10px;
}
.gender:hover{
    cursor: pointer;
    text-decoration: underline;
}

C02_D16_UseFilter2
在这里插入图片描述


login.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>登录页面</title>
        <link rel="stylesheet" href="css/style.css">
    </head>
    
    <body>
        
        <br>
        <br>
        <div  id="container">
            <br>
            <form method="post" action="ls">
                <table>
                    <caption>用户登录</caption>
                    <tr>
                        <td>账户:</td>
                        <td><input name="username" type="text" value="anna"></td>
                    </tr>
                    <tr>
                        <td>密码:</td>
                        <td><input name="password" type="password" value="123"></td>
                    </tr>
                    <tr class="foot">
                        <td colspan="2">
                            <input type="submit" value="登录">
                            <a href="#">注册</a>
                        </td>
                    </tr>
                </table>
            </form>
        </div>
        
    </body>
</html>

这里的登录和注册虽然都是按钮,但一个是提交按钮,一个是超链接。

LoginServlet

package com.qdu.servlet;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

@WebServlet("/ls")
public class LoginServlet extends HttpServlet {

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

        String uname=request.getParameter("username");
        String pwd=request.getParameter("password");
        
        if(uname.equals("anna")&&pwd.equals("123")){
            //通过请求对象可以获取关联的会话
            HttpSession session=request.getSession();
            //添加一项信息到会话对象中,表示登录状态,如果会话中有isLogin这个属性,则说明用户登录了
            session.setAttribute("isLogin","Y");
            response.sendRedirect("loginSuccess.jsp");
        }else{
            response.sendRedirect("loginFail.html");
        }
    }
}

在这里插入图片描述
loginSuccess.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <title>登录成功</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body style="background-color: darkkhaki;">
        
        <h1>欢迎登录,您可以去下载资源了</h1>
        <hr>
        <ul style="line-height: 30px;">
            <li><a href="resources/download.jsp">下载园地</a></li>
            <li><a href="resources/forum.jsp">学习论坛</a></li>
            <li><a href="resources/video.jsp">学习视频</a></li>
            <li><a href="contact.html">联系我们</a></li>
        </ul>
        <a href="los">退出登录</a>
    </body>
    
</html>

LogoutServlet

package com.qdu.servlet;

import java.io.IOException;
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 javax.servlet.http.HttpSession;

@WebServlet("/los")
public class LogoutServlet extends HttpServlet {

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

        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
        response.sendRedirect("login.html");
    }
}

在这里插入图片描述

<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <h1 style="color: red;">登录失败,请<a href="javascript:history.back();">返回</a>重新登录!</h1>
    </body>
</html>

LoginFilter

package com.qdu.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 创建一个过滤器,拦截访问resources目录下所有资源的请求
 * <br>拦截请求后判断用户是否已经登录,如果登录,放行请求访问实际资源
 * <br>否则不放行,将用户重定向到warning.html
 *
 * @author NIIT
 */
public class LoginFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init..................");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("doFilter...............");
        //getSession()方法是HttpServletRequest接口的方法,ServletRequest接口没有该方法
        //但是实际发送的请求是Http请求,所以实际发送的请求是HttpServletRequest类型
        //需要手动转换类型到HttpServletRequest类型
        HttpServletRequest req=(HttpServletRequest)request;
        //sendRedirect()方法是HttpServletResponse接口的,所以响应对象也要转换类型
        HttpServletResponse resp=(HttpServletResponse)response;
        //如果还没有会话对象,说明没登录,我们也不希望在过滤器中创建对象
        //所以调用getSession(false)表示有会话返回会话对象,没有返回null
        HttpSession session=req.getSession(false); 
        //如果会话不为null,并且会话中有isLogin这个属性(该属性不为null说明有该属性)d
        if(null!=session&&null!=session.getAttribute("isLogin")){
           chain.doFilter(request, response); //放行请求去访问资源
        }else{
            //else说明没有登录,则不调用FilterChain的doFilter()方法
            //但是这里不能使用相对路径,所以需要获取程序的上下文路径,再追加上warning.html,使用该页面的完整路径
            //该程序的上下文路径是http://localhost:8084/C02_D16_UseFilter2
            String ctxPath=req.getContextPath()+"/"; //获取程序的上下文路径
            //ctxPath+"warning.html形成的路径是http://localhost:8084/C02_D16_UseFilter2/warning.html
            resp.sendRedirect(ctxPath+"warning.html"); //这里使用warning.html的完整路径
        }
    }

    @Override
    public void destroy() {
    }
}

style.css

@charset "utf-8";

#container{
	width: 280px; 
	margin: 50px auto 0 auto;
        background-color:#CC0; 
}

table{
	width:100%;
	border-spacing: 10px;
}

table caption{
	background-color:#C60;
        padding: 10px 0 10px 0;
	font-size: 30px;
	font-weight: bold;	
        color: white;
}

input[type="text"],input[type="password"],select{
    padding:5px 10px;
    border: none;
    outline:none;
    border-radius: 5px;
}

input[type="submit"],a{
    width: 70px;
    height: 30px;
    line-height: 30px;
    background-color: darkcyan;
    color: white;
    text-align: center;
    border:none;
    border-radius: 5px;
}

a{
    display: inline-block;
    text-decoration: none;
}

input[type="submit"]:hover{
    background-color: brown;
    cursor: pointer;
}

a{
    background-color: darkorange;
}

a:hover{
    text-decoration: underline;
    background-color: brown;
}

table tr.foot{
	text-align: center;
}


web.html


    <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
    <filter>
        <description>拦截所有对resources目录下资源的访问请求,根据登录判断决定是否可以访问资源</description>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.qdu.filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/resources/*</url-pattern>
        <!--        
        /rs             拦截对rs这个servlet的访问请求
        /second.jsp     拦截对单个页面second.jsp的请求
        *.do            拦截所有以.do结尾的请求,比较常见的后缀是*.do或*.action等
        *.post          拦截所有以.post结尾的请求
        /post/*         拦截所有以post前缀的请求
        /resources/*    拦截所有以resources为前缀的请求
        /resources/*.jsp 不合法-->
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
</web-app>

C02_D17_UseFilter3

在这里插入图片描述
LoginFilter

package com.tianmao.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 创建一个过滤器,拦截访问resources目录下所有资源的请求
 * <br>拦截请求后判断用户是否已经登录,如果登录,放行请求访问实际资源
 * <br>否则不放行,将用户重定向到warning.html
 *
 * @author NIIT
 */
public class LoginFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init..................");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("doFilter...............");
        //getSession()方法是HttpServletRequest接口的方法,ServletRequest接口没有该方法
        //但是实际发送的请求是Http请求,所以实际发送的请求是HttpServletRequest类型
        //需要手动转换类型到HttpServletRequest类型
        HttpServletRequest req=(HttpServletRequest)request;
        //sendRedirect()方法是HttpServletResponse接口的,所以响应对象也要转换类型
        HttpServletResponse resp=(HttpServletResponse)response;
        //如果还没有会话对象,说明没登录,我们也不希望在过滤器中创建对象
        //所以调用getSession(false)表示有会话返回会话对象,没有返回null
        HttpSession session=req.getSession(false); 
        //如果会话不为null,并且会话中有isLogin这个属性(该属性不为null说明有该属性)d
        if(null!=session&&null!=session.getAttribute("isLogin")){
           chain.doFilter(request, response); //放行请求去访问资源
        }else{
            //else说明没有登录,则不调用FilterChain的doFilter()方法
            //但是这里不能使用相对路径,所以需要获取程序的上下文路径,再追加上warning.html,使用该页面的完整路径
            //该程序的上下文路径是http://localhost:8084/C02_D16_UseFilter2
            String ctxPath=req.getContextPath()+"/"; //获取程序的上下文路径
            //ctxPath+"warning.html形成的路径是http://localhost:8084/C02_D16_UseFilter2/warning.html
            resp.sendRedirect(ctxPath+"warning.html"); //这里使用warning.html的完整路径
        }
    }

    @Override
    public void destroy() {
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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_3_1.xsd">
 <filter>
        <description>拦截包含中文参数的post请求,判断是否登录</description>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.tianmao.filter.LoginFilter</filter-class>
    </filter>
    <!--如果想拦截某种类型的请求,可以考虑请求路径具有相同的后缀(如*.do)或前缀(如/post/*)-->
    <!--filter-mapping标记指定一个过滤器的映射,也就是过滤器过滤什么样的请求,也就是拦截什么样的请求-->

    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <!--<url-pattern>/ls</url-pattern>-->
        <!--<url-pattern>/rs</url-pattern>-->
        <url-pattern>/cs</url-pattern>
        <!--<url-pattern>/post/*</url-pattern>-->
    </filter-mapping>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <!--<url-pattern>/ls</url-pattern>-->
        <!--<url-pattern>/rs</url-pattern>-->
        <url-pattern>/los</url-pattern>
        <!--<url-pattern>/post/*</url-pattern>-->
    </filter-mapping>
     <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <!--<url-pattern>/ls</url-pattern>-->
        <!--<url-pattern>/rs</url-pattern>-->
        <url-pattern>/ps</url-pattern>
        <!--<url-pattern>/post/*</url-pattern>-->
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值