学习Java的日子 Day59 学生管理系统 web1.0版本

news2024/9/21 11:12:56

Day59 学生管理系统 web1.0

1.项目需求

有两个角色,老师和学生,相同的功能提取到父类用户角色

在这里插入图片描述

2.数据库搭建

设计学生表

在这里插入图片描述

设计老师表

在这里插入图片描述

插入数据 (超级管理员)

在这里插入图片描述

设计学科表

在这里插入图片描述

3.项目搭建

处理基础页面,分包,实体类,导入数据库

项目结构,导入数据库相关内容

在这里插入图片描述

数据库工具类

package com.qf.utils;

public class DBUtils {

    private static DruidDataSource pool;
    private static ThreadLocal<Connection> local;

    static{
        Properties properties = new Properties();
        try {
            properties.load(DBUtils.class.getClassLoader().getResourceAsStream("DBConfig.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String driverClassName = properties.getProperty("driverClassName");
        String url = properties.getProperty("url");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        int maxActive = Integer.parseInt(properties.getProperty("maxActive"));

        //初始化数据库连接池
        pool = new DruidDataSource();

        //设置参数
        pool.setDriverClassName(driverClassName);
        pool.setUrl(url);
        pool.setUsername(username);
        pool.setPassword(password);
        pool.setMaxActive(maxActive);

        local = new ThreadLocal<>();
    }

    /**
     * 获取连接对象
     */
    public static Connection getConnection() throws SQLException {
        Connection connection = local.get();//获取当前线程的Connection对象
        if(connection == null){
            connection = pool.getConnection();//获取数据库连接池里的连接对象
            local.set(connection);//将Connection对象添加到local中
        }
        return connection;
    }

    /**
     * 关闭资源
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if(connection != null){
            try {
                if(connection.getAutoCommit()){
                    connection.close();
                    local.set(null);
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 开启事务
     */
    public static void startTransaction() throws SQLException {
        Connection connection = getConnection();
        connection.setAutoCommit(false);
    }

    /**
     * 提交事务
     */
    public static void commit() throws SQLException {
        Connection connection = local.get();
        if(connection != null){
            connection.commit();
            connection.close();
            local.set(null);
        }
    }

    public static void rollback() throws SQLException {
        Connection connection = local.get();
        if(connection != null){
            connection.rollback();
            connection.close();
            local.set(null);
        }
    }

    /**
     * 更新数据(添加、删除、修改)
     */
    public static int commonUpdate(String sql,Object... params) throws SQLException {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = getConnection();
            statement = connection.prepareStatement(sql);
            paramHandler(statement,params);
            int num = statement.executeUpdate();
            return num;
        }finally {
            close(connection,statement,null);
        }
    }

    /**
     * 添加数据 - 主键回填(主键是int类型可以返回)
     */
    public static int commonInsert(String sql,Object... params) throws SQLException {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = getConnection();
            statement = connection.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
            paramHandler(statement,params);
            statement.executeUpdate();

            resultSet = statement.getGeneratedKeys();
            int primaryKey = 0;
            if(resultSet.next()){
                primaryKey = resultSet.getInt(1);
            }
            return primaryKey;
        }finally {
            close(connection,statement,resultSet);
        }
    }

    /**
     * 查询多个数据
     */
    public static <T> List<T> commonQueryList(Class<T> clazz,String sql, Object... params) throws SQLException{

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();
            statement = connection.prepareStatement(sql);
            paramHandler(statement,params);
            resultSet = statement.executeQuery();

            //获取表数据对象
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取字段个数
            int count = metaData.getColumnCount();

            List<T> list = new ArrayList<>();

            while(resultSet.next()){

                T t = null;
                try {
                    t = clazz.newInstance();
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }

                //获取字段名及数据
                for (int i = 1; i <= count; i++) {
                    String fieldName = metaData.getColumnName(i);
                    Object fieldVal = resultSet.getObject(fieldName);
                    setField(t,fieldName,fieldVal);
                }
                list.add(t);
            }
            return list;
        } finally {
            DBUtils.close(connection,statement,resultSet);
        }
    }

    /**
     * 查询单个数据
     */
    public static <T> T commonQueryObj(Class<T> clazz,String sql, Object... params) throws SQLException{

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();
            statement = connection.prepareStatement(sql);
            paramHandler(statement,params);
            resultSet = statement.executeQuery();

            //获取表数据对象
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取字段个数
            int count = metaData.getColumnCount();

            if(resultSet.next()){

                T t = null;
                try {
                    t = clazz.newInstance();
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }

                //获取字段名及数据
                for (int i = 1; i <= count; i++) {
                    String fieldName = metaData.getColumnName(i);
                    Object fieldVal = resultSet.getObject(fieldName);
                    setField(t,fieldName,fieldVal);
                }
                return t;
            }
        } finally {
            DBUtils.close(connection,statement,resultSet);
        }
        return null;
    }

    /**
     * 获取当前表的总条数
     */
    public static int getAllCount(String table) throws SQLException {
        Connection connection = getConnection();
        String sql = "select count(1) from " + table;
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){
            int allCount = resultSet.getInt(1);
            return allCount;
        }
        return 0;
    }

    /**
     * 处理statement对象参数数据的处理器
     */
    private static void paramHandler(PreparedStatement statement,Object... params) throws SQLException {
        for (int i = 0; i < params.length; i++) {
            statement.setObject(i+1,params[i]);
        }
    }

    /**
     * 获取当前类及其父类的属性对象
     * @param clazz class对象
     * @param name 属性名
     * @return 属性对象
     */
    private static Field getField(Class<?> clazz,String name){

        for(Class<?> c = clazz;c != null;c = c.getSuperclass()){
            try {
                Field field = c.getDeclaredField(name);
                return field;
            } catch (NoSuchFieldException e) {
            } catch (SecurityException e) {
            }
        }
        return null;
    }

    /**
     * 设置对象中的属性
     * @param obj 对象
     * @param name 属性名
     * @param value 属性值
     */
    private static void setField(Object obj,String name,Object value){

        Field field = getField(obj.getClass(), name);
        if(field != null){
            field.setAccessible(true);
            try {
                field.set(obj, value);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

创建首页 Welcome.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>欢迎来到学生管理系统页面</h1>
    <hr>
    <span>请选择你的操作:</span><br/>
    <a href="login.jsp">登录</a>
    <a href="register.jsp">注册</a>
</body>
</html>

web.xml配置首页

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    //设置首页
    <welcome-file-list>
        <welcome-file>Welcome.html</welcome-file>
    </welcome-file-list>
    
</web-app>

实现类创建

User

package com.qf.pojo;

public class User {
    private String username;
    private String password;
    private String name;
    private String sex;
    private int age;

//无参构造,有参构造,get,set,toString方法省略

Teacher

public class Teacher extends User{
    
    private int course;

    public Teacher() {
    }

//无参构造,有参构造带父类的属性,get,set,toString方法省略

Student

package com.qf.pojo;

public class Student extends User{

    private String hobbies;

//无参构造,有参构造带父类的属性,get,set,toString方法省略

Course

package com.qf.pojo;

public class Course {

    private int id;
    private String name;

//无参构造,有参构造,get,set,toString方法省略

4.注册功能

注册流程图

在这里插入图片描述

注册逻辑 RegisterServlet

注意:老师不用注册是管理员自动分配账号,而学生需要注册

注册逻辑:

1.设置请求、响应编码格式

2.获取请求中的数据

3.通过username查询数据库中的学生对象

4.通过学生对象进行非空判断

​ 没找到就允许注册,将数据插入到学生表中,利用重定向跳转到登录页面

​ 在数据库中就不允许注册,利用重定向跳转到注册页面

注意:

request.getParameter表示获取前端的参数,参数为页面提交的数据(二进制流不使用这个)

request.getAttribute获取请求对象(请求域)中的数据

package com.qf.Servlet;

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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        String age = request.getParameter("age");
        String[] hobbies = request.getParameterValues("hobbies");

        //通过username查询数据库中的学生对象
        Student student = null;
        try {
            student = DBUtils.commonQueryObj(Student.class, "select * from student where username=?", username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        if(student == null){//在数据库中没有找到,说明没有这个学生,就允许注册

            //将数据插入到学生表中
            try {
                DBUtils.commonUpdate("insert into student(username,password,name,sex,age,hobbies) values(?,?,?,?,?,?)",username,password,name,sex,age, StringUtils.handleArray(hobbies));
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

            //利用重定向跳转到登录页面
            response.sendRedirect("login.jsp");

        }else{//不允许注册

            //展示信息,将数据直接设置在request中
            //将数据存储到请求域中,生命周期非常短,一来一回就死亡了
            //请求发送后,响应后就死亡了
            request.setAttribute("msg","注册失败 -- 账号已存在");

            //利用转发跳转到注册页面
            request.getRequestDispatcher("register.jsp").forward(request,response);
        }

    }
}

理解以下代码

请求域对象都是使用request

//展示提示信息,将数据存储到请求对象(请求域)中,生命周期非常短,一来一回就死亡了,请求发送后,响应后就死亡了
//只是在web容器内部流转,仅仅是请求处理阶段
request.setAttribute("msg","注册失败 -- 账号已存在");

//利用转发跳转到注册页面
request.getRequestDispatcher("register.jsp").forward(request,response);   

//register.jsp前端获取
<%
    String msg = (String) request.getAttribute("msg");
%>

注册页面 register.jsp

JSP的脚本:JSP定义Java代码的方式

可以简单理解为几个标签,带有<% % >

<% java代码 %>:写的是java的逻辑代码

<%= java‘代码 %>:写的java代码,会输出展示到页面上。输出语句中可以定义什么,jsp页面就会显示什么内容

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    
<!-- 在jsp中写java代码用<% %> 包裹,拿到请求对象(请求域)中的提示信息:注册失败 -- 账号已存在 -->
<%
    String msg = (String) request.getAttribute("msg");
%>
<!-- 在页面中展示提示信息  三目运算符 第一次进入为空不展示-->
<%= (msg != null)? msg:"" %> 

<h1>注册页面</h1>
<form action="RegisterServlet" method="post">

    账号:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>
    性别:
    <input type="radio" name="sex" value="man" checked="checked"/>男
    <input type="radio" name="sex" value="woman"/>女
    <br/>
    爱好:
    <input type="checkbox" name="hobbies" value="football"/>足球
    <input type="checkbox" name="hobbies" value="basketball"/>篮球
    <input type="checkbox" name="hobbies" value="shop"/>购物
    <br/>

    <input type="submit" value="注册"/>
    <input type="button" value="返回" οnclick="goWelcome()">


</form>

<script type="text/javascript">
    function goWelcome(){
        window.location = "http://localhost:8080/StudentManagementSystem_Web_exploded/";
    }
</script>
</body>
</html>

优化注册页面 register.jsp

<!-- 在jsp中写java代码用<% %> 包裹 -->
<%
    String msg = (String) request.getAttribute("msg");
%>
<!-- 在页面中展示数据  三目运算符 第一次进入为空不展示-->
<%= (msg != null)? msg : "" %>
    
//上面的不要,直接用这一行代码展示msg(页面会自动拿到数据)
${msg}

因为hobbies是一个字符串数组,所以写一个工具类,让其拼接字符串

StringUtils

利用反射操作数组

package com.qf.utils;

import java.lang.reflect.Array;

public class StringUtils {

    public static String handleArray(Object[] os){
        StringBuffer sb = new StringBuffer();
        for (int i=0;i< Array.getLength(os);i++){//利用反射操作数组Array
            if (i!=0){
                sb.append(",");
            }

            //获取当前下标上的元素
            Object element = Array.get(os, i);
            sb.append(element);

        }

        
//        for (Object element : os) {
//            if(sb.length() !=0){
//                sb.append(",");
//            }
//            sb.append(element);
//        }
    
        return sb.toString();
    }
}

运行结果:

在这里插入图片描述

点击注册,输入数据,注册成功(账号没有在数据库里就会注册成功)跳转到登录页面,失败会跳转到注册页面,页面上会显示提示信息 注册失败 – 账号已存在

在这里插入图片描述

查看数据库

在这里插入图片描述

5.登录页面

在这里插入图片描述

LoginServlet

1.设置请求、响应编码格式

2.获取请求中的数据

3.验证码是否输入正确

​ 不正确登录失败 - 验证码错误

​ 4.正确,通过username、password查询数据库中的用户对象

​ 5.通过用户对象判断(是否在数据库中)

  					登录成功,利用重定向跳转到详情页面(凭证添加到Cookie,数据存储到Session)

  					登录失败 – 账号或密码错误,利用重定向跳转到登录页面
package com.qf.Servlet;

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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String userCode = request.getParameter("userCode");
        String rememberMe = request.getParameter("rememberMe");
        String role = request.getParameter("role");

        String sysCode = (String) request.getSession().getAttribute("sysCode");
        if (sysCode.equalsIgnoreCase(userCode)){ //验证码是否输入正确

            User user=null;
            try {
                if ("student".equals(role)){
                    user=DBUtils.commonQueryObj(Student.class,"select * from student where username=? and password=?",username,password);
                } else if ("teacher".equals(role)) {
                    user=DBUtils.commonQueryObj(Teacher.class,"select * from teacher where username=? and password=?", username, password);
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

            if (user!=null){//登录成功

                //判断是否记住我
                if(rememberMe != null){

                    //将凭证添加到Cookie中
                    //cookie保存在浏览器中
                    response.addCookie(CookieUtils.createCookie("username",user.getUsername(),60*60*24*5));
                    response.addCookie(CookieUtils.createCookie("name",user.getName(),60*60*24*5));
                    response.addCookie(CookieUtils.createCookie("role",role,60*60*24*5));

                }

                //将数据存储到Session中(后续需要使用的)
                //浏览器向服务器发送一个请求,服务器会生成一个session对象,保存在服务器中
                HttpSession session = request.getSession();
                session.setAttribute("username",user.getUsername());
                session.setAttribute("name",user.getName());
                session.setAttribute("role",role);

                response.sendRedirect("index.jsp");
            }else{//登录失败 -- 账号或密码错误
               request.setAttribute("msg","登录失败--账号或密码错误");
               request.getRequestDispatcher("login.jsp").forward(request,response);
            }

        }else{//登录失败 - 验证码错误
            //将数据发送到请求对象(请求域)中,时间在一瞬间,交互很短
            //我们使用request.setAttribute()方法设置了一个名为 “msg” 的属性,并将其值设置为 “登录失败--验证码错误”。
            // 然后,我们可以通过请求转发(forward)将这个属性传递给其他组件,如另一个Servlet或JSP页面
            request.setAttribute("msg","登录失败--验证码错误");
            request.getRequestDispatcher("login.jsp").forward(request,response);
        }


    }
}

login.jsp

关注验证码的写法,还有就是刷新验证码和点击验证码自动刷新

注意设置刷新验证码的函数

<%@ page import="java.net.URLDecoder" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<!-- 记住我的代码 -->
<%
    Cookie[] cookies = request.getCookies();

    if(cookies != null){
        int count = 0;
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            String value = URLDecoder.decode(cookie.getValue(),"UTF-8");

            if("username".equals(name)){
                session.setAttribute("username",value);
                count++;
            }
            if("name".equals(name)){
                session.setAttribute("name",value);
                count++;
            }
            if("role".equals(name)){
                session.setAttribute("role",value);
                count++;
            }
        }

        if(count == 3){
            response.sendRedirect("index.jsp");
        }

    }
%>

    
    
<!-- 判断登录结果,成功还是失败,提示信息显示在页面上方 -->
<%
    String msg = (String) request.getAttribute("msg");
%>
<%= (msg!=null)?msg:""%>
    
    
    

<h1>登录页面</h1>
<!--点击登录页面,会方式两次请求,一次是LoginServlet,第二次是CodeServlet-->
<form action="LoginServlet" method="post">

    账号:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    验证码:<input type="text" name="userCode"/><img src="CodeServlet" width="120px" height="30px" οnclick="refresh()"><a href="#" οnclick="refresh()">刷新</a><br/>
    记住我:<input type="checkbox" name="rememberMe"/><br/>
    角色:
    <select name="role">
        <option value="student">学生</option>
        <option value="teacher">老师</option>
    </select>
    <br/>
    <input type="submit" value="登录"/>
    <input type="button" value="返回" οnclick="goWelcome()"/>
</form>

<script type="text/javascript">
    function goWelcome(){
        window.location = "welcome.html";
    }

    //刷新验证码
    img = document.getElementsByTagName("img")[0];
    function refresh(){
        img.src = "CodeServlet?" + new Date();
    }
    
</script>

</body>
</html>


优化login.jsp

<%@ page import="java.net.URLDecoder" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<!-- 记住我的java代码直接写出去 rememberMe.jsp,然后导包 -->
<%@include file="rememberMe.jsp"%>


<!-- 判断登录结果,成功还是失败,显示在页面上方 -->
<%--<%--%>
<%--    String msg = (String) request.getAttribute("msg");--%>
<%--%>--%>
<%--<%= (msg!=null)?msg:""%>--%>

${msg}

<h1>登录页面</h1>
<!--点击登录页面,会方式两次请求,一次是LoginServlet,第二次是CodeServlet-->
<form action="LoginServlet" method="post">

    账号:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    
...省略

</body>
</html>


java代码直接写出去 rememberMe.jsp,然后导包

rememberMe.jsp

<%@ page import="java.net.URLDecoder" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    Cookie[] cookies = request.getCookies();

    if(cookies != null){
        int count = 0;
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            String value = URLDecoder.decode(cookie.getValue(),"UTF-8");

            if("username".equals(name)){

                session.setAttribute("username",value);
                count++;
            }
            if("name".equals(name)){
                session.setAttribute("name",value);
                count++;
            }
            if("role".equals(name)){
                session.setAttribute("role",value);
                count++;
            }
        }

        if(count == 3){
            response.sendRedirect("index.jsp");
        }

    }
%>

5.1 绘制验证码

CodeServlet

1.创建画布(前提定义宽高)

2.通过画布获取画笔

3.设置背景色 – 填充矩形【利用画笔】

4.设置验证码

创建验证码数字数组、颜色数组

利用随机数进行获取随机下标从而获取随机数字和颜色

设置随机颜色

设置字体(字体,样式,大小)

设置单个验证码

StringBffer拼接成验证码

设置干扰线

6.ImageIO将画布以jpg形式的文件传出给客户端

package com.qf.Servlet;

@WebServlet("/CodeServlet")
public class CodeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

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

        //验证码是图片,不需要编码格式
        
        //设置宽高的变量
        int width = 120;
        int height = 30;

        //创建画布
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        //获取画笔
        Graphics graphics = image.getGraphics();

        //设置背景色 -- 填充矩形
        graphics.setColor(Color.BLUE);//选择颜色
        graphics.fillRect(0,0,width,height);//填充整个图片区域

        //设置验证码
        Random random = new Random();
        String[] codes = {"A","B","C","D","E","F","G","H","J","K","M","N","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9"};
        Color[] colors = {Color.CYAN,Color.BLACK,Color.GREEN,Color.PINK,Color.WHITE,Color.RED,Color.ORANGE};

        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < 4; i++) {

            String randomCode = codes[random.nextInt(codes.length)];//随机内容
            Color randomColor = colors[random.nextInt(colors.length)];//随机颜色

            graphics.setColor(randomColor);//设置随机颜色
            graphics.setFont(new Font("宋体",Font.BOLD,20+random.nextInt(10)));//设置字体(字体,样式,大小)
            graphics.drawString(randomCode,20+i*25,15+random.nextInt(10));//设置单个验证码

            sb.append(randomCode);
        }

        //将系统验证码设置到Session对象中(会话对象),存储在服务器中
        //浏览器向服务器发送一个请求,服务器会生成一个session对象
        HttpSession session = request.getSession();//获取请求里的JSESSIONID(客户端Cookie里的数据),如果没有就创建Session对象,如果有就从Session容器中获取会话对象
        session.setAttribute("sysCode",sb.toString());//键值对,键是String类型,值是Object对象

        //设置干扰线
        graphics.setColor(Color.YELLOW);
        for (int i = 0; i < 3; i++) {
            graphics.drawLine(random.nextInt(width),random.nextInt(height),random.nextInt(width),random.nextInt(height));//绘制直线(x1,y1,x2,y2) -> 两点为一线
        }

        //将画布以jpg形式的文件传出给客户端,ImageIO工具
        ImageIO.write(image,"jpg",response.getOutputStream());

    }
}

5.2 分析验证码功能制作

在这里插入图片描述

注册功能中的request.getAttribute:将数据直接设置在request中,利用request调用,存储时间短

验证码功能中的HttpSession session = request.getSession(); 浏览器向服务器发送一个请求,服务器会生成一个session对象,利用session(request.getSession() )去调用,30分钟

区别:session的过期时间是30分钟,可以调,长时间的属性可以放在session,一瞬间的数据可以放在jsp里请求对象request里

session对象的作用域为一次会话,通常浏览器不关闭,保存的值就不会消失,当然也会出现session超时(tomcat默认为30分钟)

session.getAttribute(“”) 取到的类型是是object,所以赋值前要强转一下 ,转成你需要的类型

Session的基本工作原理:

  1. 用户访问Web应用程序时,服务器为每个用户创建一个唯一的Session对象。
  2. 服务器将Session ID 分配给每个Session对象,并将Session ID 存储在用户的浏览器中的Cookie中。Session ID 在服务器端和客户端之间用于标识Session。
  3. 当用户发送请求时,服务器使用Session ID 来查找相应的Session对象。
  4. 服务器可以将数据存储在Session对象中,以便在用户的不同请求之间共享。
  5. 当用户关闭浏览器或Session超时时,Session对象被销毁。

session的相关使用

1.获取Session对象,使用的是request对象

HttpSession session = request.getSession();

2.存储数据到 session 域中

session.setAttribute(String name, Object o)

3.根据 key,获取值

session.getAttribute(String name)

验证码功能就是把把验证码存在session对象中,设置键值对属性

输入一个验证码,会寻找对应的session ID,获取对应的值,这个有30分钟,不同的验证码请求有不同的ID

	//将系统验证码设置到Session对象中(会话对象)
    //浏览器向服务器发送一个请求,服务器会生成一个session对象
    HttpSession session = request.getSession();//获取请求里的JSESSIONID(客户端Cookie里的数据),如果没有获取到就创建Session对象,如果有就从Session容器中获取会话对象
    session.setAttribute("sysCode",sb.toString());//键值对,键是String类型,值是Object对象


从Session对象中取出来判断

request.getSession() -->获取到这个session对象,再获取里面的value

     //从Session对象中获取系统的验证码
     String sysCode = (String) request.getSession().getAttribute("sysCode");
     if(sysCode.equalsIgnoreCase(userCode)){
		......
     }

结论

1.Cookie是用来保证用户在未登录情况下的身份识别

2.Session是用来保存用户登录后的数据

3.Session是存储在服务端,而Cookie是存储在客户端

4.购物车、记住我功能:使用Cookie来存储

5.以登录用户的名称展示、验证码:使用Session来存储

运行结果:

输入一个在数据库有的数据

在这里插入图片描述

在这里插入图片描述

5.3 记住我(存Session、存Cookie)

流程图

在这里插入图片描述

在这里插入图片描述

实现:存Session、存Cookie

LoginServlet

添加存凭证

1.当第一次登录时,点击了“记住我”,就会存凭证【username、name、role合起来是一个凭证】存在Cookie中

2.再次登录就会判断,是否有凭证

  有,直接跳详情页面,不过在跳转前会将凭证存在session中【因为详情页展示需要session的数据】

​ 没有,就不管,就用户直接输入登录

package com.qf.Servlet;

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


        String sysCode = (String) request.getSession().getAttribute("sysCode");
        if (sysCode.equalsIgnoreCase(userCode)){ //验证码是否输入正确

            User user=null;
            try {
                if ("student".equals(role)){
                    user=DBUtils.commonQueryObj(Student.class,"select * from student where username=? and password=?",username,password);
                } else if ("teacher".equals(role)) {
                    user=DBUtils.commonQueryObj(Teacher.class,"select * from teacher where username=? and password=?", username, password);
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

            if (user!=null){//登录成功

                //判断是否记住我
                if(rememberMe != null){

                    //将凭证添加到Cookie中
                    //cookie保存在客户端中(键值对都是String类型)
                    response.addCookie(CookieUtils.createCookie("username",user.getUsername(),60*60*24*5));
                    response.addCookie(CookieUtils.createCookie("name",user.getName(),60*60*24*5));
                    response.addCookie(CookieUtils.createCookie("role",role,60*60*24*5));

                }

                //将凭证数据存储到Session中
                //浏览器向服务器发送一个请求,服务器会生成一个session对象,保存在服务器中
                HttpSession session = request.getSession();
                session.setAttribute("username",user.getUsername());
                session.setAttribute("name",user.getName());
                session.setAttribute("role",role);

                response.sendRedirect("index.jsp");
            }else{//登录失败 -- 账号或密码错误
               request.setAttribute("msg","登录失败--账号或密码错误");
               request.getRequestDispatcher("login.jsp").forward(request,response);
            }

添加cookie工具类

CookieUtils

package com.qf.utils;

public class CookieUtils {
    public static Cookie createCookie(String name,String value,int time)  {
        Cookie cookie=null;
        try {
            //数据中有中文,必须设置编码格式
            cookie= new Cookie(name, URLEncoder.encode(value, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        cookie.setMaxAge(time);
        return  cookie;
    }
}


login.jsp

<%@ page import="java.net.URLDecoder" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<!-- 记住我的代码 -->
<%
    Cookie[] cookies = request.getCookies();

    if(cookies != null){
        int count = 0;
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            //取数据时需要解码
            String value = URLDecoder.decode(cookie.getValue(),"UTF-8");

            if("username".equals(name)){
                //存储value值
                session.setAttribute("username",value);
                count++;
            }
            if("name".equals(name)){
                session.setAttribute("name",value);
                count++;
            }
            if("role".equals(name)){
                session.setAttribute("role",value);
                count++;
            }
        }

        if(count == 3){
            response.sendRedirect("index.jsp");
        }

    }
%>

<!-- 判断登录结果,成功还是失败,显示在页面上方 -->
<%
    String msg = (String) request.getAttribute("msg");
%>
<%= (msg!=null)?msg:""%>

<h1>登录页面</h1>

    .......

Cookie:

1.创建Cookie对象,并设置值:

Cookie cookie = new Cookie("key","value");

2.发送Cookie到客户端使用的是Reponse对象:

response.addCookie(cookie);

3.获取Cookie:使用Request对象获取Cookie数组:

Cookie[] cookies = request.getCookies();

6.详情页

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    //取出登录页面存储的session对象
    String username = (String) session.getAttribute("username");
    String name = (String) session.getAttribute("name");
    String role = (String) session.getAttribute("role");
%>

<button onclick="safeExit()">安全退出</button>
<h1>详情页面</h1>
<h1>欢迎<%=name%><%=("student".equals(role))?"学员":""%><%=("teacher".equals(role))?"老师":""%>进入到学生管理系统</h1>

<a href="resetPassword.jsp">修改密码</a>


<%if("student".equals(role)){%>
<!-- 在这个servlet通过username找到这个学生,再跳转到信息修改页面 -->
<a href="StuInitModifyServlet?username=<%=username%>">修改信息</a>
<%}%>

<%if("teacher".equals(role)){%>
<a href="TeaInitModifyServlet?username=<%=username%>">修改信息</a>
<a href="#">查看所有学生</a>
<%}%>

<script type="text/javascript">
    function safeExit(){
        window.location = "SafeExitServlet";
    }
</script>
</body>
</html>


优化:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>


<html>
<head>
    <title>Title</title>
</head>
<body>
<%--<%--%>
<%--    String username = (String) session.getAttribute("username");--%>
<%--    String name = (String) session.getAttribute("name");--%>
<%--    String role = (String) session.getAttribute("role");--%>
<%--%>--%>


<button onclick="safeExit()">安全退出</button>
<h1>详情页面</h1>
<%--<%=("student".equals(role))?"学员":""%>--%>
<%--${(role eq "student")?"学员":""}--%>

<h1>欢迎${name}${(role eq "student")?"学员":""}${(role eq "teacher")?"学员":""}进入到学生管理系统</h1>

<a href="resetPassword.jsp">修改密码</a>

<c:if test="${role eq 'student'}">
    <a href="StuInitModifyServlet?username=${username}">修改信息</a>
</c:if>

<%--<%if("student".equals(role)){%>--%>
<%--<!-- 在这个servlet通过username找到这个学生,再跳转到信息修改页面 -->--%>
<%--<a href="StuInitModifyServlet?username=<%=username%>">修改信息</a>--%>
<%--<%}%>--%>

<%--<%if("teacher".equals(role)){%>--%>
<%--<a href="TeaInitModifyServlet?username=<%=username%>">修改信息</a>--%>
<%--<a href="GetStuListServlet?curPage=1">查看所有学生</a>--%>
<%--<%}%>--%>

<c:if test="${role eq 'teacher'}">
    <a href="TeaInitModifyServlet?username=${usename}">修改信息</a>
    <a href="GetStuListServlet?curPage=1">查看所有学生</a>
</c:if>

<script type="text/javascript">
    function safeExit(){
        window.location = "SafeExitServlet";
    }
</script>
</body>
</html>


8.安全退出(删Session、删Cookie)

删除账号所有信息 cookie,session

<button οnclick="safeExit()">安全退出</button>
<h1>详情页面</h1>
<h1>欢迎<%=name%><%=("student".equals(role))?"学员":""%><%=("teacher".equals(role))?"老师":""%>进入到学生管理系统</h1>
    
<script type="text/javascript">
    function safeExit(){
        window.location = "SafeExitServlet";
    }
</script>

SafeExitServlet

package com.qf.Servlet;
import com.qf.utils.CookieUtils;

@WebServlet("/SafeExitServlet")
public class SafeExitServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

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

        //删除Cookie里的数据
        //把时间设置为0,就是删除
        response.addCookie(CookieUtils.createCookie("username","",0));
        response.addCookie(CookieUtils.createCookie("name","",0));
        response.addCookie(CookieUtils.createCookie("role","",0));

        //删除Session里的数据
        HttpSession session = request.getSession();
        session.removeAttribute("username");
        session.removeAttribute("name");
        session.removeAttribute("role");

        //跳转
        response.sendRedirect("Welcome.html");
    }
}

9.修改密码

在这里插入图片描述

index.jsp

<button onclick="safeExit()">安全退出</button>
<h1>详情页面</h1>
<h1>欢迎<%=name%><%=("student".equals(role))?"学员":""%><%=("teacher".equals(role))?"老师":""%>进入到学生管理系统</h1>

<a href="resetPassword.jsp">修改密码</a>

// ...省略

resetPassword.jsp

需要展示页面就要先获取session中的username

要用户输入原密码和新密码【对于为什么要原密码,就是在用户电脑在登录情况下被别人直接改密码】

注意1:对于ResetPasswordServlet查询用户对象,是需要username和role,怎么获取?

方案:在这个表单直接请求传过去(使用隐藏域),ResetPasswordServlet就可以在请求中取

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    //从前端页面中取出来数据(当前页面没用,但是后面的ResetPasswordServlet有用)
    String username = (String) session.getAttribute("username");
    String role = (String) session.getAttribute("role");

    //提示信息
    String msg = (String) request.getAttribute("msg");
%>
    
<%=(msg!=null)?msg:""%>
    

<form action="ResetPasswordServlet" method="post">

    //传入给后端ResetPasswordServlet
    <!--隐藏域,不会在页面中展示,但是发送请求后会携带到后端-->
    <input type="hidden" name="username" value="<%=username%>"/>
    <input type="hidden" name="role" value="<%=role%>"/>

    账号:<%=username%><br/>
    原密码:<input type="password" name="password"/><br/>
    新密码:<input type="password" name="newPassword"/><br/>

    <input type="submit" value="修改"/>
    <input type="button" value="返回" οnclick="goIndex()"/>
</form>

<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>


ResetPasswordServlet

1.设置请求、响应编码格式
2.获取请求中的数据
3.通过username、password查询数据库中的用户对象
4.通过用户对象进行非空判断
用户存在,判断角色修改密码,注意要做安全退出【不然在有记住我的情况下,第二次登录直接进来】

​ 用户不存在,设置提示修改密码失败信息,又转发方式跳转回到修改密码页面

package com.qf.Servlet;

@WebServlet("/ResetPasswordServlet")
public class ResetPasswordServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

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

        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String newPassword = request.getParameter("newPassword");
        String role = request.getParameter("role");

        User user=null;
        try {
            //判断角色
            if ("student".equals(role)) {
                user= DBUtils.commonQueryObj(Student.class,"select * from student where username=? and password=?", username, password);

            } else if ("teacher".equals(role)) {
                user= DBUtils.commonQueryObj(Teacher.class,"select * from teacher where username=? and password=?", username, password);
            }

            if (user!=null){//修改
                if ("student".equals(role)){
                    DBUtils.commonUpdate("update student set password=? where username=?",newPassword,username);
                } else if ("teacher".equals(role)) {
                    DBUtils.commonUpdate("update teacher set password=? where username=?",newPassword,username);
                }
                //修改密码成功后,做安全退出的功能
                //修改密码了,相当于退出了
                request.getRequestDispatcher("SafeExitServlet").forward(request,response);

            }else {//修改密码失败--原密码不正确
                request.setAttribute("msg","修改密码失败--原密码不正确");
                request.getRequestDispatcher("resetPassword.jsp").forward(request,response);
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }


    }
}

10.修改学生信息(StuInitModifyServlet、StuModifyServlet)

index.jsp

不能直接跳转到修改信息页面,因为拿不到session数据,需要中间页面StuInitModifyServlet(页面跳页面获取学生信息)

在路径中传username, 使StuInitModifyServlet可以拿到账号到数据库查询到改账号的学生信息

<h1>详情页面</h1>

<%if("student".equals(role)){%>
<!-- 在这个servlet通过username找到这个学生,再跳转到信息修改页面 -->
<a href="StuInitModifyServlet?username=<%=username%>">修改信息</a>
<%}%>


StuInitModifyServlet

操作:初始化修改学生数据

  1. 设置请求、响应编码格式
  2. 获取请求中的数据
  3. 从数据库中获取学生对象
  4. 将学生对象存在请求中,转发方式到学生修改信息页面stuInfo.jsp
package com.qf.Servlet;

@WebServlet("/StuInitModifyServlet")
public class StuInitModifyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");

        //从数据库中获取学生对象
        Student student = null;
        try {
            student = DBUtils.commonQueryObj(Student.class, "select * from student where username=?", username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        request.setAttribute("student",student);
        request.getRequestDispatcher("stuInfo.jsp").forward(request,response);
    }
}

stuInfo.jsp

对于没有学生信息,需要先到StuInitModifyServlet获取到学生对象,再获取其中信息,上传到stuInfo.jsp,用来修改页面展示和表单发送StuModifyServlet中的修改

注意:对性别和爱好的选择处理

<%@ page import="com.qf.pojo.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    Student student = (Student) request.getAttribute("student");
%>

<h1>学生修改信息页面</h1>

<form action="StuModifyServlet" method="post">

    <input type="hidden" name="username" value="<%=student.getUsername()%>"/>

    账号:<%=student.getUsername()%><br/>
    姓名:<input type="text" name="name" value="<%=student.getName()%>"/><br/>
    年龄:<input type="text" name="age" value="<%=student.getAge()%>"/><br/>
    
    性别:
    <input type="radio" name="sex" value="man" <%=(student.getSex().equals("man"))?"checked='checked'":""%>/>男
    <input type="radio" name="sex" value="woman" <%=(student.getSex().equals("woman"))?"checked='checked'":""%>/>女
    <br/>
    
    爱好:
    <input type="checkbox" name="hobbies" value="football" <%=(student.getHobbies().contains("football"))?"checked='checked'":""%>/>足球
    <input type="checkbox" name="hobbies" value="basketball" <%=(student.getHobbies().contains("basketball"))?"checked='checked'":""%>/>篮球
    <input type="checkbox" name="hobbies" value="shop" <%=(student.getHobbies().contains("shop"))?"checked='checked'":""%>/>购物
    <br/>

    <input type="submit" value="修改"/>
    <input type="button" value="返回" οnclick="goIndex()"/>
</form>

<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>


优化:

主要是jsp的EL和JSTL表达式的改进

<%@ page import="com.qf.pojo.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%--<%--%>
<%--    Student student = (Student) request.getAttribute("student");--%>
<%--%>--%>

<h1>学生修改信息页面</h1>

<form action="StuModifyServlet" method="post">

    <input type="hidden" name="username" value="${student.username}"/>

    账号:${student.username}<br/>
    姓名:<input type="text" name="name" value="${student.name}"/><br/>
    年龄:<input type="text" name="age" value="${student.age}"/><br/>
    性别:
    <input type="radio" name="sex" value="man" ${(student.sex eq 'man')?"checked='checked'":""}/>男
    <input type="radio" name="sex" value="woman" ${(student.sex eq 'woman')?"checked='checked'":""}/>女
    <br/>
    爱好:
    <input type="checkbox" name="hobbies" value="football" <c:if test="${fn:contains(student.hobbies, 'football')}">checked='checked'</c:if>/>足球
    <input type="checkbox" name="hobbies" value="basketball" <c:if test="${fn:contains(student.hobbies, 'basketball')}">checked='checked'</c:if>/>篮球
    <input type="checkbox" name="hobbies" value="shop" <c:if test="${fn:contains(student.hobbies, 'shop')}">checked='checked'</c:if>/>购物
    <br/>

    <input type="submit" value="修改"/>
    <input type="button" value="返回" οnclick="goIndex()"/>
</form>

<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>


StuModifyServlet(修改学生信息的逻辑)

1.设置请求、响应编码格式
2.获取请求中的数据
3.更新数据库里的学生数据
4.更新Session里的数据【原因:可能改名字,如果不改还是原来的名字就会在使用时出错】
5.更新Cookie里的数据【可存可不存,还是存一下,Cookie只有记住我才会有数据,name涉及凭证】
6.重定向方式跳转到详情页面index.jsp

package com.qf.Servlet;

@WebServlet("/StuModifyServlet")
public class StuModifyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        String age = request.getParameter("age");
        String[] hobbies = request.getParameterValues("hobbies");

        //更新数据库里的学生数据
        try {
            DBUtils.commonUpdate("update student set name=?,sex=?,age=?,hobbies=? where username=?",name,sex,age, StringUtils.handleArray(hobbies),username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        String role = (String) request.getSession().getAttribute("role");

        if("student".equals(role)){
            //更新Session里的数据
            request.getSession().setAttribute("name",name);
            //更新Cookie里的数据
            response.addCookie(CookieUtils.createCookie("name",name,60*60*24*5));
            //跳转详情页面
            response.sendRedirect("index.jsp");
        }else if("teacher".equals(role)){
            //跳转
            response.sendRedirect("GetStuListServlet?curPage=1");
        }
    }
}

11.修改老师信息(TeaInitModifyServlet、TeaModifyServlet)

详情页面 index.js

通过username拿到老师数据,交给request对象

<h1>详情页面</h1>

<%if("student".equals(role)){%>
<!-- 在这个servlet通过username找到这个学生,再跳转到信息修改页面 -->
<a href="StuInitModifyServlet?username=<%=username%>">修改信息</a>
<%}%>

//省略

TeaInitModifyServle

操作:初始化修改老师数据

  1. 设置请求、响应编码格式
  2. 获取请求中的数据
  3. 从数据库中获取老师对象
  4. 将老师对象和课程集合对象存在请求中,转发方式到老师修改信息页面teaInfo.jsp
package com.qf.Servlet;

@WebServlet("/TeaInitModifyServlet")
public class TeaInitModifyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");

        //从数据库中获取相应的数据
        Teacher teacher = null;
        List<Course> courses = null;
        try {
            teacher = DBUtils.commonQueryObj(Teacher.class,"select * from teacher where username=?",username);
            courses = DBUtils.commonQueryList(Course.class,"select * from course");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //存入请求对象中
        request.setAttribute("teacher",teacher);
        request.setAttribute("courses",courses);

        //跳转页面
        request.getRequestDispatcher("teaInfo.jsp").forward(request,response);
    }
}

teaInfo.jsp(老师修改信息页面)

需要先到TeaInitModifyServlet获取到老师对象,再获取其中信息,用来修改页面展示和表单发送TeaModifyServlet中的修改

注意:对性别和学科选择的处理

对于学科考虑到会新增的情况,不能写死,通过获取学科集合再遍历的方式进行选择展示

<%@ page import="com.qf.pojo.Teacher" %>
<%@ page import="java.util.List" %>
<%@ page import="com.qf.pojo.Course" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    Teacher teacher = (Teacher) request.getAttribute("teacher");
    List<Course> courses = (List<Course>) request.getAttribute("courses");
%>

<h1>老师修改信息页面</h1>

<form action="TeaModifyServlet" method="post">

    <input type="hidden" name="username" value="<%=teacher.getUsername()%>"/>

    账号:<%=teacher.getUsername()%><br/>
    姓名:<input type="text" name="name" value="<%=teacher.getName()%>"/><br/>
    年龄:<input type="text" name="age" value="<%=teacher.getAge()%>"/><br/>
    性别:
    <input type="radio" name="sex" value="man" <%=(teacher.getSex().equals("man"))?"checked='checked'":""%>/><input type="radio" name="sex" value="woman" <%=(teacher.getSex().equals("woman"))?"checked='checked'":""%>/><br/>
    学科:
    <select>
        <%for(Course course:courses){%>
        <option value="<%=course.getId()%>" <%=(course.getId() == teacher.getCourseId())?"selected='selected'":""%> ><%=course.getName()%></option>
<%}%>
    </select>
    <br>

    <input type="submit" value="修改"/>
    <input type="button" value="返回" onclick="goIndex()"/>
</form>

<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>



优化:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page import="com.qf.pojo.Course" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--<%--%>
<%--    Teacher teacher = (Teacher) request.getAttribute("teacher");--%>
<%--    List<Course> courses = (List<Course>) request.getAttribute("courses");--%>
<%--%>--%>

<h1>老师修改信息页面</h1>

<form action="TeaModifyServlet" method="post">

    <input type="hidden" name="username" value="${teacher.username}"/>

    账号:${teacher.username}<br/>
    姓名:<input type="text" name="name" value="${teacher.name}"/><br/>
    年龄:<input type="text" name="age" value="${teacher.age}"/><br/>
    性别:
    <input type="radio" name="sex" value="man" ${(teacher.sex eq 'man')?"checked='checked'":""}/><input type="radio" name="sex" value="woman" ${(teacher.sex eq 'woman')?"checked='checked'":""}/><br/>
    学科:
    <select name="courseId">

        <c:forEach items="${courses}" var="course">
            <option value="${course.id}"  <c:if test="${course.id == teacher.courseId}">selected='selected'</c:if> >${course.name}</option>
        </c:forEach>
    </select>
    <br/>

    <input type="submit" value="修改"/>
    <input type="button" value="返回" onclick="goIndex()"/>
</form>


<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>


TeaModifyServlet

设置请求、响应编码格式
获取请求中的数据
更新数据库里的老师数据
更新Session里的数据【原因:可能改名字,如果不改还是原来的名字就会在使用时出错】
更新Cookie里的数据【可存可不存,还是存一下,Cookie只有记住我才会有数据,name涉及凭证】
重定向方式跳转到详情页面index.jsp

package com.qf.Servlet;

@WebServlet("/TeaModifyServlet")
public class TeaModifyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        String age = request.getParameter("age");
        String courseId = request.getParameter("courseId");

        //更新数据库里的学生数据
        try {
            DBUtils.commonUpdate("update teacher set name=?,sex=?,age=?,courseId=? where username=?",name,sex,age, courseId,username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //更新Session里的数据
        request.getSession().setAttribute("name",name);
        //更新Cookie里的数据
        response.addCookie(CookieUtils.createCookie("name",name,60*60*24*5));

        response.sendRedirect("index.jsp");
    }
}

12.老师角色查询所有学生

要用分页技术

在这里插入图片描述

在这里插入图片描述

index.jsp

不能直接跳stuList.jsp,没数据

TeaInitModifyServlet?username=<%=username%>:拼接一下,传数据

<h1>详情页面</h1>

<%if("teacher".equals(role)){%>
<a href="TeaInitModifyServlet?username=<%=username%>">修改信息</a>
<a href="GetStuListServlet?curPage=1">查看所有学生</a>
<%}%>

</script>
</body>
</html>


GetStuListServlet

拿数据和分页

package com.qf.Servlet;

@WebServlet("/GetStuListServlet")
public class GetStuListServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取当前页数
        int curPage = Integer.parseInt(request.getParameter("curPage"));

        //设置当前页的数据条数
        int count = 15;
        //计算偏移量
        int offset = (curPage-1)*count;
        //计算总页数
        int totalPage;
        try {
            int allCount = DBUtils.getAllCount("student");
            if(allCount % count == 0){
                totalPage = allCount/count;
            }else{
                totalPage = allCount/count + 1;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //从数据库获取学生的集合
        List<Student> students = null;
        try {
            students = DBUtils.commonQueryList(Student.class, "select * from student limit ?,?", offset, count);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //处理学生集合
        List<StudentDto> studentDtos = DtoUtils.studentDtoListHandler(students);

        //将数据存入到请求对象中
        request.setAttribute("curPage",curPage);
        request.setAttribute("totalPage",totalPage);
        request.setAttribute("studentDtos",studentDtos);

        //跳转
        request.getRequestDispatcher("stuList.jsp").forward(request,response);

    }
}

stuList.jsp,学生列表页面

添加学生信息处理后获取

<%@ page import="java.util.List" %>
<%@ page import="com.qf.pojo.Student" %>
<%@ page import="com.qf.dto.StudentDto" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    List<StudentDto> studentDtos = (List<StudentDto>) request.getAttribute("studentDtos");
    int curPage = (int) request.getAttribute("curPage");
    int totalPage = (int) request.getAttribute("totalPage");
%>

<button οnclick="doIndex()">返回</button>
<h1>学生列表页面</h1>

<table border="1" width="500px">

    <tr>
        <th>账号</th>
        <th>姓名</th>
        <th>性别</th>
        <th>年龄</th>
        <th>爱好</th>
        <th>操作</th>
    </tr>

    //遍历,数据渲染
    <%for (StudentDto studentDto:studentDtos){%>
        <tr>
            <th><%=studentDto.getStudent().getUsername()%></th>
            <th><%=studentDto.getStudent().getName()%></th>
            <th><%=studentDto.getSex()%></th>
            <th><%=studentDto.getStudent().getAge()%></th>
            <th><%=studentDto.getHobbies()%></th>
            <th>
                <a href="StuInitModifyServlet?username=<%=studentDto.getStudent().getUsername()%>">修改</a>
                <a href="StuDeleteServlet?username=<%=studentDto.getStudent().getUsername()%>">删除</a>
            </th>
        </tr>
    <%}%>
</table>

//分页
<a href="GetStuListServlet?curPage=1">首页</a>

	//第一页的时候不能有上一页
<%if(curPage > 1){%>
<a href="GetStuListServlet?curPage=<%=curPage-1%>">上一页</a>
<%}%>
    //最后一页的时候不能有下一页
<%if(curPage < totalPage){%>
<a href="GetStuListServlet?curPage=<%=curPage+1%>">下一页</a>
<%}%>
<a href="GetStuListServlet?curPage=<%=totalPage%>">尾页</a>

<script type="text/javascript">
    function goIndex(){
        window.location = "index.jsp";
    }
</script>
</body>
</html>

DBUtils 数据库工具类

获取当前表的总条数

    public static int getAllCount(String table) throws SQLException {
        Connection connection = getConnection();
        String sql = "select count(1) from " + table;
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){
            int allCount = resultSet.getInt(1);
            return allCount;
        }
        return 0;
    }

Student

做分页的假数据

    public static void main(String[] args) {
        for (int i = 10; i < 100; i++) {
            String username = "xiaohei" + i;
            String password = "123123";
            String name = "小黑" + i;
            String sex = "man";
            int age = 23;
            String[] hobbies = {"football", "basketball"};
            try {
                DBUtils.commonUpdate("insert into student(username,password,name,sex,age,hobbies) values(?,?,?,?,?,?)", username, password, name, sex, age, StringUtils.handleArray(hobbies));
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

运行结果:

在这里插入图片描述

性别是man,爱好是英语,不方便观看,需要转成中文

包装学生类,写一个bto包,原来的student类不满足需求

分包新增信息处理类,以方便工具类对学生的信息处理

StudentDto

package com.qf.dto;

public class StudentDto {

    private Student student;
    private String sex;
    private String hobbies;

//无参构造,有参构造,get,set,toString类

}

写一个工具类

DtoUtils

工具类,处理学生信息提升页面展示效果 ,然后在GetStuListServlet里操作

package com.qf.utils;

public class DtoUtils {

    public static StudentDto studentDtoHandler(Student student) {

        //处理学生的性别数据
        String sex = student.getSex();
        if ("man".equals(sex)) {
            sex = "男";
        } else if ("woman".equals(sex)) {
            sex = "女";
        }

        //处理学生的爱好数据(做替换)
        String hobbies = student.getHobbies();
        hobbies = hobbies.replaceAll("football", "足球");
        hobbies = hobbies.replaceAll("basketball", "篮球");
        hobbies = hobbies.replaceAll("shop", "购物");

        //创建StudentDto
        StudentDto studentDto = new StudentDto(student, sex, hobbies);
        return studentDto;
    }

    public static List<StudentDto> studentDtoListHandler(List<Student> students){
        ArrayList<StudentDto> studentDtos = new ArrayList<>();

        for (Student student:students){
            StudentDto studentDto = studentDtoHandler(student);
            studentDtos.add(studentDto);
        }
        return studentDtos;
    }
}

12.1 优化分页

GetStuListServlet

多了一个这个:设置URL:String url = “GetStuListServlet?curPage=”;

package com.qf.Servlet;

@WebServlet("/GetStuListServlet")
public class GetStuListServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取当前页数
        int curPage = Integer.parseInt(request.getParameter("curPage"));

        //设置URL
        String url = "GetStuListServlet?curPage=";
        //设置当前页的数据条数
        int count = 15;
        //计算偏移量
        int offset = (curPage-1)*count;
        //计算总页数
        int totalPage;
        try {
            int allCount = DBUtils.getAllCount("student");
            if(allCount % count == 0){
                totalPage = allCount/count;
            }else{
                totalPage = allCount/count + 1;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //从数据库获取学生的集合
        List<Student> students = null;
        try {
            students = DBUtils.commonQueryList(Student.class, "select * from student limit ?,?", offset, count);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //处理学生集合
        List<StudentDto> studentDtos = DtoUtils.studentDtoListHandler(students);

        //封装Page对象
        Page<StudentDto> page = new Page<>(url, curPage, totalPage, studentDtos);

        //将数据存入到请求对象中
        request.setAttribute("page",page);
        

        //跳转
        request.getRequestDispatcher("stuList.jsp").forward(request,response);

    }
}

上面的请求对象太多了,同一设置一个page类

原来是这个:

//将数据存入到请求对象中
request.setAttribute(“curPage”,curPage);
request.setAttribute(“totalPage”,totalPage);
request.setAttribute(“studentDtos”,studentDtos);

package com.qf.pojo;

public class Page<T> {

    private String url;
    private int curPage;
    private int totalPage;
    private List<T> list;
//省略

page.jsp

把分页放在外面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<a href="${page.url}1">首页</a>
<c:if test="${page.curPage > 1}">
    <a href="${page.url}${page.curPage-1}">上一页</a>
</c:if>
<c:if test="${page.curPage < page.totalPage}">
    <a href="${page.url}${page.curPage+1}">下一页</a>
</c:if>
<a href="${page.url}${page.totalPage}">尾页</a>

13.老师角色操作学生的修改

学生的修改写了的,就是StuInitModifyServlet

stuList.jsp

<%for (StudentDto studentDto:studentDtos){%>
        <tr>
            <th><%=studentDto.getStudent().getUsername()%></th>
            <th><%=studentDto.getStudent().getName()%></th>
            <th><%=studentDto.getSex()%></th>
            <th><%=studentDto.getStudent().getAge()%></th>
            <th><%=studentDto.getHobbies()%></th>
            <th>
                <a href="StuInitModifyServlet?username=<%=studentDto.getStudent().getUsername()%>">修改</a>
                <a href="StuDeleteServlet?username=<%=studentDto.getStudent().getUsername()%>">删除</a>
            </th>
        </tr>
    <%}%>

StuInitModifyServlet,跳转到StuModifyServlet

获取角色

1.通过角色判断修改

2.学生需要更新Session、Cookie里的数据,跳转详情页面

3.老师跳转GetStuListServlet,需要更新数据【因为修改了需要刷新页面】

(老师这里不需要修改cookie和session,最后一步不一样)

package com.qf.Servlet;

@WebServlet("/StuModifyServlet")
public class StuModifyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求、响应编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //获取请求中的数据
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        String age = request.getParameter("age");
        String[] hobbies = request.getParameterValues("hobbies");

        //更新数据库里的学生数据
        try {
            DBUtils.commonUpdate("update student set name=?,sex=?,age=?,hobbies=? where username=?",name,sex,age, StringUtils.handleArray(hobbies),username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        String role = (String) request.getSession().getAttribute("role");

        if("student".equals(role)){
            //更新Session里的数据
            request.getSession().setAttribute("name",name);
            //更新Cookie里的数据
            response.addCookie(CookieUtils.createCookie("name",name,60*60*24*5));
            //跳转详情页面
            response.sendRedirect("index.jsp");
        }else if("teacher".equals(role)){
            //跳转
            response.sendRedirect("GetStuListServlet?curPage=1");
        }
    }
}

14.老师角色操作学生的删除

stuList.jsp

<h1>学生列表页面</h1>

    <%for (StudentDto studentDto:studentDtos){%>
        <tr>
            <th><%=studentDto.getStudent().getUsername()%></th>
            <th><%=studentDto.getStudent().getName()%></th>
            <th><%=studentDto.getSex()%></th>
            <th><%=studentDto.getStudent().getAge()%></th>
            <th><%=studentDto.getHobbies()%></th>
            <th>
                <a href="StuInitModifyServlet?username=<%=studentDto.getStudent().getUsername()%>">修改</a>
                <a href="StuDeleteServlet?username=<%=studentDto.getStudent().getUsername()%>">删除</a>
            </th>
        </tr>
    <%}%>
</table>

</body>
</html>

StuDeleteServlet

设置编码格式,获取请求中的账号,通过学生账号删除学生,最后跳转GetStuListServlet同时更新数据

注意:实际开发项目中是不会直接用delete,而是改状态,数据库有提到

package com.qf.Servlet;

@WebServlet("/StuDeleteServlet")
public class StuDeleteServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

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

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");

        try {
            DBUtils.commonUpdate("delete from student where username=?",username);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //跳转
        response.sendRedirect("GetStuListServlet?curPage=1");

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977429.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微软AI业务最新营收数据情况(2024年7月)

Azure AI 年度经常性收入 (ARR)&#xff1a;达到50亿美元客户数量&#xff1a;60,000家平均客户价值 (ACV) 中位数&#xff1a;83,000美元同比增长率&#xff1a;达到了惊人的900% GitHub Copilot 年度经常性收入 (ARR)&#xff1a;达到3亿美元客户数量&#xff1a;77,000家…

每日两题8

买卖股票的最佳时机 III class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();int INF 0x3f3f3f3f;vector<vector<int>> f(n, vector<int>(3, -INF));auto g f;g[0][0] 0;f[0][0] -prices[0];for (int i 1; i…

Leetcode3227. 字符串元音游戏

Every day a Leetcode 题目来源&#xff1a;3227. 字符串元音游戏 解法1&#xff1a;博弈论 分类讨论&#xff1a; 如果 s 不包含任何元音&#xff0c;小红输。如果 s 包含奇数个元音&#xff0c;小红可以直接把整个 s 移除&#xff0c;小红赢。如果 s 包含正偶数个元音&am…

10.Redis类型SortedSet

介绍 Redis的SortedSet是一个可排序的set集合。与java的TreeSet有些类似&#xff0c;但底层数据结构却差别很大。 SortedSet中的每个元素都带有一个score属性&#xff0c;可以基于score属性对元素排序&#xff0c;底层实现是一个跳表SkipList加hash表。 特点 可排序 元素不…

“银狐”团伙再度出击:利用易语言远控木马实施钓鱼攻击

PART ONE 概述 自2023年上半年“银狐”工具被披露以来&#xff0c;涌现了多个使用该工具的黑产团伙。这些团伙主要针对国内的金融、教育、医疗、高新技术等企事业单位&#xff0c;集中向管理、财务、销售等从业人员发起攻击&#xff0c;窃取目标资金和隐私信息。该团伙惯用微信…

多旋翼+四光吊舱:5Kg负载无人机技术详解

多旋翼无人机是一种具有三个及以上旋翼轴的无人驾驶飞行器。它通过每个轴上的电动机转动&#xff0c;带动旋翼&#xff0c;从而产生升推力。旋翼的总距固定&#xff0c;不像一般直升机那样可变。通过改变不同旋翼之间的相对转速&#xff0c;可以控制飞行器的运行轨迹。多旋翼无…

Js在线Eval加密混淆及解密运行

具体请前往&#xff1a;Js在线Eval加密混淆及解密运行

自动打电话软件的效果怎么样?

​​使用这个系统&#xff0c;机器人自动拨打电话&#xff0c;真人录制的语音与客户对话&#xff0c;整个过程非常顺畅。而且系统可以每天外呼数千乃至数万通电话&#xff0c;是人工的5-10倍&#xff0c;这样就不需要招聘大量员工来外呼&#xff0c;只需要留下一些优秀的销售人…

动视封禁超过6.5万名《战区》和《MW3》作弊者

动视已经在《使命召唤&#xff1a;战区》和《使命召唤&#xff1a;现代战争3》中封禁了超过65000名玩家。这些封禁在过去的几小时内实施&#xff0c;清除了数千名在排名赛和非排名赛中“作弊和代练”的玩家。 Ricochet反作弊团队现已清理了《使命召唤&#xff1a;战地》和《现代…

【PyTorch】神经风格迁移项目

神经风格迁移中&#xff0c;取一个内容图像和一个风格图像&#xff0c;综合内容图像的内容和风格图像的艺术风格生成新的图像。 目录 准备数据 处理数据 神经风格迁移模型 加载预训练模型 定义损失函数 定义优化器 运行模型 准备数据 创建data文件夹&#xff0c;放入…

人工智能与大数据的融合:驱动未来的力量

人工智能与大数据的融合&#xff1a;驱动未来的力量 一、人工智能与大数据的概述二、人工智能与大数据在数据库中的融合三、实际应用案例四、未来发展方向总结 【纪录片】中国数据库前世今生 在数字化潮流席卷全球的今天&#xff0c;数据库作为IT技术领域的“活化石”&#xff…

16进制转换-系统架构师(三十九)

1、&#xff08;软件架构设计->构件与中间件技术->构件标准&#xff09;对象管理组织&#xff08;OMG&#xff09;基于CORBA基础设施定义了四种构件标准。其中&#xff0c;&#xff08;&#xff09;状态信息是构件自身而不是由容器维护的。 A实体构件 B加工构件 C服务…

C++中lambda使用mutable关键字详解

C中lambda使用mutable关键字详解 在《C初学者指南-5.标准库(第二部分)–更改元素算法》中&#xff0c;讲“generate”算法时有下面这段代码&#xff1a; auto gen [i0]() mutable { i 2; return i; }; std::vector<int> v; v.resize(7,0); generate(begin(v)1, begin…

(南京观海微电子)——LCD OTP(烧录)介绍

OTP OTP只是一种存储数据的器件&#xff0c;全写:ONETIMEPROGRAM。 OTP目的&#xff1a;提高产品的一致性 客户端的接口不支持和我们自己的产品IC之间通信&#xff0c;即不支持写初始化&#xff0c;所以产品的电学功能以及光学特性需要固化在IC中&#xff0c;所以需要我们来进行…

青甘环线游记|day(1)|兰州

出发 下午1点&#xff0c;登机。航班经停万州&#xff0c;再到兰州。下图为飞机上拍的照片&#xff0c;不知道为什么窗户上有结晶的东西&#xff08;&#xff1f;&#xff09; 在飞机上拍的航线图&#xff0c;但是有点模糊。飞机上有提供午餐。4点左右到达万州 在飞机上好像…

08 Redis Set类型操作与使用场景

Redis Set类型操作与使用场景 一、Set类型操作 ​ Redis的Set结构与Java中的HashSet类似&#xff0c;可以看做是一个value为null的HashMap。因为也是一个hash表&#xff0c;因此具备与HashSet类似的特征&#xff1a; ​ 无序 ​ 元素不可重复 ​ 查找快 ​ 支持交集、并集…

Tomcat 8.5 下载、安装、启动及各种问题

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 本期内容主要介绍 Tomcat 8 的安装&#xff0c;以及可能会遇到的问题 文章目录 1. Tomcat 安装2. 可能会遇到的问题2.…

pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

重新设置一下环境变量。 注意&#xff0c;这里后面没有斜杠 我之前就是因为环境变量中&#xff0c;这两行最后都有斜杠&#xff0c;导致提示pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Multi-AP

1. Multiple-BSSID 和Multi-VAP Multiple-BSSID 和Multi-VAP差异&#xff1a; Multi-VAP&#xff1a; 每个AP独自发送beacon帧&#xff1b; Multiple-BSSID&#xff1a; 所有AP公用一个beacon帧。 1.1 Multi-VAP 如果您使用过 Wi-Fi &#xff08;2.4/5.0GHz&#xff09;&am…

著名ROM修改社区停止运营 管理员与继任者互相指责

运营近二十年的知名ROM修改社区网站Romhacking.net即将关闭新内容的提交和更新。网站创始人Nightcrawler表示&#xff0c;网站已经“几乎完成了最初设定的所有目标&#xff0c;并且远远超出了预期。”然而&#xff0c;根据其他网站工作人员的说法&#xff0c;事情似乎没那么简单…