JavaWeb学生管理系统(详细源码+解析)

news2024/11/18 13:32:44


很多人大学的第一个小项目就是使用JavaWeb实现了一个学生管理系统或者是图书管理系统。在没有项目经验的情况下,前后端都需要自己去完成,还是要耗费不少时间精力的。本次我就分享一下我在大学期间完成的第一个小项目:学生管理系统。采用的技术有:Thymeleaf+Ajax+HTML+JQuery+Java+MySQL。下面会进行详细介绍,也可以关注微信公众号【橙晴丰Ciao】,私信我获取项目源码:JavaWeb学生管理系统。

效果演示

在这里插入图片描述
如何实现上面图片所实现的效果呢?接下来我将进行一个简单介绍。

项目搭建

  • 安装好Java环境【验证方式:同时点击win+r输入java -version】
  • 安装好MySQL环境
  • 先→创建一个JavaWeb项目,然后再实现具体的功能。

项目结构

JavaWeb项目搭建好后,就可以进行开发了,为了让第一次学习的小伙伴更加清楚地知道项目结构,我先把开发好后的结构图展示一下:
在这里插入图片描述

数据库搭建

在MySQL数据库中创建一个student_info数据库,用于存储我们要操作的学生信息表以及管理员登录表。

CREATE DATABASE student_info;

DROP TABLE IF EXISTS `t_login`;
CREATE TABLE `t_login` (
  `user_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `user_password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_login
-- ----------------------------
INSERT INTO `t_login` VALUES ('admin', 'admin');

-- ----------------------------
-- Table structure for `t_student`
-- ----------------------------
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student` (
  `student_id` int(11) NOT NULL AUTO_INCREMENT,
  `student_name` varchar(100) DEFAULT NULL,
  `student_class` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1704134100 DEFAULT CHARSET=utf8;

项目开发

项目对数据库的操作是必不可少的,所以我们先进行数据库方面的配置。在resource文件夹中进行数据库连接方面的配置:

常用配置

druid.properties

数据库可能存在时区问题,根据报错提示网上查找解决方案修改url即可

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student_info?  
username=root
password=root
initialSize=5
maxActive=10
maxWait=1000

JDBCUtil

src/utils工具包中创建JDBCUtil工具类进行数据库连接等操作:

package com.lzk.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtil {
    private static DataSource dataSource;
    static {
        try {
            //读取配置文件,创建连接池
            InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            //使用DruidDataSourceFactory创建连接池
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池
     * @return
     */
    public static DataSource getDataSource(){
        return dataSource;
    }

    /**
     * 获取连接
     * @return
     */
    public static Connection getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 归还连接的方法
     * @param connection
     */
    public static void releaseConnection(Connection connection){
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }
}

BaseDao

src/utils工具包中创建BaseDao工具类进行数据增删改查等操作:

package com.lzk.utils;


import com.lzk.utils.JDBCUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class BaseDao<T> {
    private QueryRunner queryRunner = new QueryRunner();
    /**
     * 批处理方法
     * @param sql
     * @param paramArr
     * @return
     */
    public int[] batchUpdate(String sql,Object[][] paramArr){
        Connection conn = JDBCUtil.getConnection();
        try {
            return queryRunner.batch(conn,sql,paramArr);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            JDBCUtil.releaseConnection(conn);
        }
    }
    /**
     * 执行增删改的sql语句
     * @param sql
     * @param params
     * @return
     */
    public int update(String sql,Object... params){
        Connection conn = JDBCUtil.getConnection();
        //执行增删改的sql语句,返回受到影响的行数
        try {
            return queryRunner.update(conn,sql,params);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            JDBCUtil.releaseConnection(conn);
        }
    }
    /**
     * 执行查询一行数据的sql语句,将结果集封装到JavaBean对象中
     * @param clazz
     * @param sql
     * @param params
     * @return
     */
    public T getBean(Class<T> clazz,String sql,Object... params){
        Connection conn = JDBCUtil.getConnection();

        try {
            return queryRunner.query(conn,sql,new BeanHandler<>(clazz),params);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            JDBCUtil.releaseConnection(conn);
        }
    }
    /**
     * 执行查询多行数据的sql语句,并且将结果集封装到List<JavaBean>
     * @param clazz
     * @param sql
     * @param params
     * @return
     */
    public List<T> getBeanList(Class<T> clazz, String sql, Object... params){
        Connection conn = JDBCUtil.getConnection();
        try {
            return queryRunner.query(conn,sql,new BeanListHandler<>(clazz),params);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            JDBCUtil.releaseConnection(conn);
        }
    }
    //查询数据条数
    public long findCount(String sql, Object... params) throws SQLException {
        Connection conn = JDBCUtil.getConnection();
        try {
            long count= queryRunner.query(conn,sql,new ScalarHandler<>(),params);
            return count;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            JDBCUtil.releaseConnection(conn);
        }
    }

}

数据模型层

User

用户实体类,跟数据库中的t_login表对应,存储管理员的信息。要有构造方法(无参、多参)以及getter和setter方法。

public class User {
    private String userId;
    private String userPassword;
}

Student

学生实体类,对应学生信息表。要有构造方法(无参、多参)以及getter和setter方法。

public class Student {
    private Integer studentId;
    private String studentName;
    private String studentClass;
}

PageInfo

分页信息实体类,不涉及数据库存储,只用于分页信息展示。要有构造方法(无参、多参)以及getter和setter方法。

public class PageInfo {

    //当前页 currentPage
    private Long currentPage;
    
    //页面大小
    private Long pageSize = 5L;

    //总数据totalCount
    private Long totalCount;

    //总页数totalPage
    private Long totalPage;
    
    //上一页
    private Long previousPage;
    
    //下一页
    private Long nextPage;
}

以上实体类都需要有getter和setter方法,否则在进行Thymeleaf模板渲染时就会出错。

web.xml配置文件

这个文件在web/WEB-INF,可以通过配置此文件进行控制层的映射。

<?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">
    
    <!-- 把首页指向portalServlet,表示请求路径为/时,交由portalServlet进行处理 -->
    <welcome-file-list>
        <welcome-file>portalServlet</welcome-file>
        <!-- 也可以通过这种方式配置首页,但login页面有使用thymeleaf语法,直接使用静态资源访问方式需要进行页面变量修改 -->
        <!--        <welcome-file>/WEB-INF/view/login.html</welcome-file>-->
    </welcome-file-list>
    <!-- 在上下文参数中配置视图前缀和视图后缀,这个是使用了Thymeleaf后需要进行配置的,
    表示经过servlet渲染后返回的页面的路径以及后缀 -->
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/WEB-INF/view/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>
    <!-- 这个servlet由项目中哪个包下的servlet进行处理 -->
    <servlet>
        <servlet-name>PortalServlet</servlet-name>
        <servlet-class>com.lzk.servlet.model.PortalServlet</servlet-class>
    </servlet>
	<!-- 处理请求学生数据时路径的映射配置 -->
	 <servlet-mapping>
        <servlet-name>StudentServlet</servlet-name>
        <url-pattern>/student</url-pattern>
    </servlet-mapping>
	
    <servlet>
        <servlet-name>StudentServlet</servlet-name>
        <servlet-class>com.lzk.servlet.model.StudentServlet</servlet-class>
    </servlet>
	
    <servlet>
        <servlet-name>CodeServlet</servlet-name>
        <servlet-class>com.lzk.servlet.model.CodeServlet</servlet-class>
    </servlet>
     <servlet-mapping>
        <servlet-name>CodeServlet</servlet-name>
        <url-pattern>/code</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>PortalServlet</servlet-name>
        <url-pattern>/portalServlet</url-pattern>
    </servlet-mapping>
</web-app>

经过上面的配置后,当访问首页/时,就会交由portalServlet进行处理。

ProtalServlet

package com.lzk.servlet.model;

import com.lzk.servlet.base.ViewBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class PortalServlet extends ViewBaseServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //解析模板
        processTemplate("login", request, response);
    }
}

protalServlet进行请求处理时会将login页面进行渲染后返回,之所以可以实现模板渲染,是因为继承了ViewBaseServlet类。

ViewBaseServlet

这个类是基于Thymeleaf实现的可以进行模板渲染,继承自该类的所有子实现类也具有相同的功能。

package com.lzk.servlet.base;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

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

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

login页面

在ProtalServlet中会进行模板渲染login页面,也就是登录时候的界面。因为我们在web.xml中进行了模板渲染视图上下文配置,所以该页面需要在/WEB-INF/view/中,并且为html形式。

这个页面就是一个登录表单,就是样式比较多

<!doctype html>
<html lang="zh-CN" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/favicon.ico">
    <link rel="canonical" href="https://getbootstrap.com/docs/3.4/examples/signin/">

    <title>学生管理系统登录界面</title>
    <!-- Bootstrap core CSS -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">

    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/examples/signin/signin.css" rel="stylesheet">

    <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/assets/js/ie8-responsive-file-warning.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/assets/js/ie-emulation-modes-warning.js"></script>

    <script language="javascript" th:inline="javascript">
        function flushCode() {
            // 每次刷新的时候获取当前时间,防止浏览器缓存刷新失败
            var time = new Date();
            document.getElementById("scode").src="/StudentManage01/code?method=imageCode&time="+time;
        }
    </script>
    <style type="text/css">
        body{
            background-size:auto,auto;
            background-repeat: no-repeat;
        }
        .code-class{
            position: relative;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            padding: 10px;
            font-size: 16px;
            color: inherit;
            font: inherit;
            margin: 0;
            width: 180px;
            height: 44px;
            line-height: 1.42857143;
            color: #555;
            background-color: #fff;
            background-image: none;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
            -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
            transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
        }
        .identity{vertical-align: middle;height: 34px}
    </style>
</head>

<body>

<div class="container">

    <form class="form-signin" th:action="@{/student(method='Login')}" method="post">
        <h1>LOGIN</h1>
        <input type="text" id="inputEmail" name="userId" class="form-control" placeholder="账号" required autofocus>
        <br/>

        <input type="password" id="inputPassword" name="userPassword" class="form-control" placeholder="密码" required>

        <div >
            <input type="text" id="inputCode" name="code" class="code-class" placeholder="验证码" required>
            <img alt="验证码" id="scode" class="identity" onclick="flushCode()" th:src="@{/code(method='imageCode')}" >
        </div>
        <br/>

        <input class="btn btn-lg btn-primary btn-block" type="submit" value="登录"><br/>
    </form>

</div>

<script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/assets/js/ie10-viewport-bug-workaround.js"></script>
</body>
</html>

登录页面使用了bootstrap,但是采用的是在线方式导入样式,所以需要联网才能显示效果。
可以看到页面有一个验证码的图片,这个验证码是通过后端进行绘制后返回给前端页面的。
访问的路径为:/StudentManage01/code?method=imageCode&time="+time;
在web.xml中有进行验证码路径的相关配置,发起的/code请求会交由CodeServlet进行处理。跟ProtalServlet一样,但是这里多了两个参数。我们先看下CodeServlet是怎么对验证码进行处理的。

CodeConstant

验证码图片长宽的参数定义。

public class CodeConstant {

    // 图片高度
    public static final int IMG_HEIGHT = 100;

    // 图片宽度
    public static final int IMG_WIDTH = 30;

    // 验证码长度
    public static final int CODE_LEN = 4;

}

CodeServlet

package com.lzk.servlet.model;

import com.lzk.constant.CodeConstant;
import com.lzk.servlet.base.ModelBaseServlet;

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

public class CodeServlet extends ModelBaseServlet {

    public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // 用于绘制图片,设置图片的长宽和图片类型(RGB)
        BufferedImage bi = new BufferedImage(CodeConstant.IMG_HEIGHT, CodeConstant.IMG_WIDTH, BufferedImage.TYPE_INT_RGB);
        // 获取绘图工具
        Graphics graphics = bi.getGraphics();
        graphics.setColor(new Color(100, 230, 200)); // 使用RGB设置背景颜色
        graphics.fillRect(0, 0, 100, 30); // 填充矩形区域

        // 验证码中所使用到的字符
        char[] codeChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456".toCharArray();
        String captcha = ""; // 存放生成的验证码
        Random random = new Random();
        for(int i = 0; i < CodeConstant.CODE_LEN; i++) { // 循环将每个验证码字符绘制到图片上
            int index = random.nextInt(codeChar.length);
            // 随机生成验证码颜色
            graphics.setColor(new Color(random.nextInt(150), random.nextInt(200), random.nextInt(255)));
            // 将一个字符绘制到图片上,并制定位置(设置x,y坐标)
            graphics.drawString(codeChar[index] + "", (i * 20) + 15, 20);
            captcha += codeChar[index];
        }
        // 将生成的验证码code放入sessoin中
        request.getSession().setAttribute("code", captcha);
        // 通过ImageIO将图片输出
        ImageIO.write(bi, "JPG", response.getOutputStream());
    }
}

这个类中对请求的处理跟ProtalServlet不一样,他有更具体的方法进行处理,而ProtalServlet是只针对Post请求和Get请求进行处理,而Post请求又调用Get请求的方法,因此ProtalServlet对请求只有一种应对方法,当然要想访问ProtalServlet也只能通过/进行。也就是一个请求路径对应一个Servlet,不管参数怎么变,对应的Servlet最多只能对不同请求进行两种不同的处理,一种为客户端发起Post请求时进行的处理,一种为Get。这种方式会非常繁琐,一是每个请求路径都要在web.xml进行配置,二是不好管理,例如对学生信息的增删改查,要写四个Servlet,而这四个Servlet关联性又很强。所以我们引入了ModelBaseServlet。

ModelBaseServlet

这个Servlet继承了ViewBaseServlet,所以也有模板渲染的功能并且通过暴力反射的方式去获取当前访问的方法名进行调用。所以当前端页面发起/StudentManage01/code?method=imageCode&time="+time;请求时,就会路径映射到codeServlet并且暴力反射调用CodeServlet中的imageCode。这种方式就可以实现针对CodeServlet中对验证码不同请求有多种不同的处理方式,只需要在里面写不同的方法即可。

package com.lzk.servlet.base;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

public class ModelBaseServlet extends ViewBaseServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        //获取请求参数method的值
        String method = request.getParameter("method");
        //method参数的值就是要调用的方法的方法名,那就是已知方法名要去查找调用本对象的方法
        try {
            Method declaredMethod = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            //暴力反射
            declaredMethod.setAccessible(true);
            //调用方法
            declaredMethod.invoke(this,request,response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

StudentServlet

现在是对学生信息数据方面的处理,通过该Servlet实现学生数据的增删改查。在这个Servlet中就可以看到引入的ModelBaseServlet的作用。里面可以实现四个方法,请求时只需要通过method参数指定请求的方法即可。
在登录页面点击登录按钮后会向@{/student(method='login')}发起请求,即调用login方法进行验证,成功则到list页面,失败则到·error页面。该servlet需渲染的页面后面都会提供。
Servlet在进行业务处理时会调用Service层,Servcie层调用Dao层。

package com.lzk.servlet.model;

import com.lzk.bean.PageInfo;
import com.lzk.bean.Student;
import com.lzk.service.StudentService;
import com.lzk.service.impl.StudentServiceImpl;
import com.lzk.servlet.base.ModelBaseServlet;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.*;
import java.util.List;

public class StudentServlet extends ModelBaseServlet {
    //创建Service对象
    private StudentService studentService = new StudentServiceImpl();

    //删除学生信息
    public void deleteStudent(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Integer id = Integer.valueOf(request.getParameter("id"));
        studentService.deleteStudentById(id);
    }

    //跳转到学生信息修改页面
    public void toStudentInfoPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取要修改的学生的id
        Integer id = Integer.valueOf(request.getParameter("id"));
        Long currentPage =  Long.valueOf(request.getParameter("currentPage"));

        Student student = new Student();
        Long pageSize = new PageInfo().getPageSize();
        //查询出当前学生的信息
        try {
            //查询指定学生信息
            if(!id.equals(-1)){
                student = studentService.findStudentById(id);
            }
            if(currentPage.equals(-1)){
                currentPage = studentService.getPageInfo(1L, pageSize).getTotalPage();
            }
            //将student存储到请求域中
            request.setAttribute("currentPage",currentPage);
            request.setAttribute("student", student);
            //跳转到修改页面
            processTemplate("student-update", request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //修改和增加学生信息
    public void updateOrAddStudent(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        Long currentPage = Long.valueOf(parameterMap.get("currentPage")[0]);
        Long pageSize = new PageInfo().getPageSize();
        if(currentPage==-1){
            currentPage = studentService.getPageInfo(1L, pageSize).getTotalPage()-1;
        }
        //将请求参数封装到Student对象
        Student student = new Student();
        try {
            BeanUtils.populate(student, parameterMap);
            System.out.println(student.toString());
            //调用业务层的方法执行修改
            if(student.getStudentId()!=null){
                studentService.updateStudent(student);
            }else{
                studentService.insertStudent(student);
            }
            request.setAttribute("currentPage",currentPage);
            processTemplate("list", request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //登录:查找登录用户是否存在
    public void login(HttpServletRequest request, HttpServletResponse response) throws Exception {
        long count = -1;
        try{
            //获取要登录的用户的id
            String id = String.valueOf(request.getParameter("userId"));
            //获取要登录的用户的密码
            String password = String.valueOf(request.getParameter("userPassword"));

            //调用业务层的方法查询用户是否存在
            count = studentService.findExistStudent(id, password);
            //验证码
            String code = (String) request.getSession().getAttribute("code");
            // 获取页面提交的验证码
            String inputCode = request.getParameter("code");
            //登录成功要同时满足用户存在且验证码正确
            boolean equals_code = code.toLowerCase().equals(inputCode.toLowerCase());
            if (count > 0 && equals_code) {
                //查询成功,解析Thymeleaf模板
                processTemplate("list", request, response);
            } else if(!equals_code){
                request.setAttribute("errorMsg", "验证码错误");
                processTemplate("error", request, response);
            } else {
                request.setAttribute("errorMsg", "用户不存在");
                processTemplate("error", request, response);
            }

        } catch (Exception e) {
            e.printStackTrace();
            //跳转到统一的异常提示页面
            request.setAttribute("errorMsg", e.getMessage());
            processTemplate("error", request, response);
        }

    }

    //获取分页学生列表数据
    public void getStudentList(HttpServletRequest request, HttpServletResponse response) throws Exception {

        Map<String, String[]> parameterMap = request.getParameterMap();

        //将请求参数封装到PageStudent对象
        PageInfo pageStudent = new PageInfo();

        //将请求域中的数据与每个pageStudent对应起来
        BeanUtils.populate(pageStudent, parameterMap);

        Long currentPage = pageStudent.getCurrentPage();
        Long pageSize = pageStudent.getPageSize();

        pageStudent = studentService.getPageInfo(currentPage, pageSize);
        //调用业务层的方法查询某一页的学生信息,所以currentPage需要前端处理好访问哪一页后传递过来
        List<Student> studentList = studentService.findStudentByPage(currentPage);
        //将pageStudent存储到请求域中
        request.setAttribute("pageInfo", pageStudent);
        //将某一页的学生信息存储到request一个名为list的对象中
        request.setAttribute("list", studentList);
        //跳转到展示页面
        processTemplate("student-table", request, response);

    }
}

StudentService

根据面向接口编程的原则,所以先实现这个接口。

面向接口的好处:当具体的业务逻辑要进行变更时,不需要改变Servlet层的代码,只需要重新写一个实现类去实现该接口,当然原先的接口也可以保存下来,只需要在导入实现类包的时候选择最新的那个。

package com.lzk.service;

import com.lzk.bean.PageInfo;
import com.lzk.bean.Student;

import java.sql.SQLException;
import java.util.List;

public interface StudentService {

    //查询某一页学生信息
    List<Student> findStudentByPage(long pagenumber) throws Exception;

    //删除学生信息
    public void deleteStudentById(Integer id) throws Exception;

    //添加学生信息
    public void insertStudent(Student student) throws Exception;

    //查询指定学生信息
    public Student findStudentById(Integer id) throws Exception ;

    //修改学生信息
    public void updateStudent(Student student) throws Exception;

    //查询学生是否存在
    public long findExistStudent(String id,String name) throws Exception;

    //查询学生总数
    public long findAllStudentCount() throws Exception;

    //返回学生的分页导航数据
    PageInfo getPageInfo(Long currentPage, Long pageSize) throws Exception;

}

StudentServiceImpl

package com.lzk.service.impl;


import com.lzk.bean.PageInfo;
import com.lzk.bean.Student;
import com.lzk.dao.StudentDao;
import com.lzk.dao.impl.StudentDaoImpl;
import com.lzk.service.StudentService;

import java.sql.SQLException;
import java.util.List;

public class StudentServiceImpl implements StudentService {
    //创建Dao对象
    private StudentDao studentDao = new StudentDaoImpl();

    //查询某一页学生信息
    @Override
    public List<Student> findStudentByPage(long currentpage) throws Exception {
        return studentDao.findStudentByPage(currentpage);
    }

    //删除学生信息
    @Override
    public void deleteStudentById(Integer id) throws Exception{
        studentDao.deleteStudentById(id);
    }
    //添加学生信息
    @Override
    public void insertStudent(Student student) throws Exception {
        studentDao.insertStudent(student);
    }
    //查询指定学生信息
    @Override
    public Student findStudentById(Integer id) throws Exception {
        return studentDao.findStudentById(id);
    }
    //修改学生信息
    @Override
    public void updateStudent(Student student) throws Exception {
        studentDao.updateStudent(student);
    }
    //查询学生是否存在
    public long findExistStudent(String id,String password) throws Exception{
        return studentDao.findExistStudent(id, password);
    }
    //查询学生总数
    public long findAllStudentCount() throws Exception{
        return studentDao.findAllStudnetCount();
    }

    @Override
    public PageInfo getPageInfo(Long currentPage,Long pageSize) throws SQLException {
        long totalCount = studentDao.findAllStudnetCount();
        long totalPage = totalCount % pageSize == 0 ? totalCount/pageSize : totalCount/pageSize + 1;
        Long nextPage = null;
        Long previousPage = null;
        if(currentPage < totalPage-1){
            nextPage = currentPage + 1;
        }
        if(currentPage != 0){
            previousPage = currentPage - 1;
        }
        PageInfo pageInfo = new PageInfo(currentPage,pageSize,totalCount,totalPage,previousPage,nextPage);
        return pageInfo;
    }
}

StudentDao

Service需要调用Dao层

为什么要分为三层,而不让StudentService直接处理完呢?
其实每一层都有对应的功能,servlet负责请求的处理,service负责具体的业务逻辑处理,dao层负责对数据库数据的处理。分为三层可以解耦合,让结构更为清晰。

package com.lzk.dao;

import com.lzk.bean.PageInfo;
import com.lzk.bean.Student;

import java.sql.SQLException;
import java.util.List;

public interface StudentDao {
    //查询所有学生信息
    List<Student> findAll() throws SQLException;

    //查询某一页学生信息
    List<Student> findStudentByPage(long pagenumber) throws SQLException;

    //删除学生信息
    void deleteStudentById(Integer id) throws SQLException;

    //添加学生信息
    void insertStudent(Student student) throws SQLException;

    //查询指定学生信息
    Student findStudentById(Integer id) throws SQLException;

    //修改学生信息
    void updateStudent(Student student) throws SQLException;

    //根据学号,姓名查询学生是否存在,k
    long findExistStudent(String id,String password) throws SQLException;

    //查询数据总数
    long findAllStudnetCount() throws SQLException;


}

list页面

list页面只展示导航条部分数据,学生数据是通过页面加载时发起th:onload="|getStudentListByPage(${currentPage == null ? 0 : currentPage})|"请求去获取的。这个方法在后面的student.js里。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>展示学生列表信息</title>

    <!-- Bootstrap core CSS -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/dist/css/bootstrap.min.css" rel="stylesheet">

    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">

    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.25/examples/dashboard/dashboard.css" rel="stylesheet">

    <script src="js/jquery-1.8.3.js"></script>
    <script src="js/student.js"></script>
</head>
<body th:onload="|getStudentListByPage(${currentPage == null ? 0 : currentPage})|">
    <div>
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container-fluid">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">学生信息管理系统</a>
                </div>

            </div>
        </nav>

        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                    <li><a th:onclick="getStudentListByPage(0)" style="cursor: pointer">分页学生信息</a></li>
                    <li><a th:onclick="toStudentInfoPage(-1,-1)" style="cursor: pointer">添加学生信息</a></li>
                </ul>
            </div>

            <div id="content"></div>
        </div>
    </div>
</body>
</html>

student.js

第一次发起的请求为:student?method=getStudentList&currentPage=0,这个请求还是通过web.xml中配置的StudentServlet处理,处理逻辑看上面的StudentServlet中的getStudentList方法。其中的PageInfo包装了分页信息。

//异步加载学生信息列表
function getStudentListByPage(currentPage) {
    $.ajax({
        url: 'student?method=getStudentList&currentPage='+currentPage,
        type: 'GET',
        success: function(response) {
            $("#content").empty();
            $("#content").html(response)
        }
    });
}
//删除学生信息
function deleteStudentById(studentId,currentPage) {
    $.ajax({
        url: 'student?method=deleteStudent&id=' + studentId,
        type: 'GET',
        success: function () {
            getStudentListByPage(currentPage);
        }
    });
}

function showAppointPage() {
    var current = document.getElementById("appointPage").value;
    getStudentListByPage(current-1);
}

function toStudentInfoPage(studentId,currentPage) {
    $.ajax({
        url: 'student',
        type: 'GET',
        data: { 'method': 'toStudentInfoPage', 'id': studentId, 'currentPage': currentPage},
        success: function(response) {
            $("#content").empty();
            $("#content").html(response)
        }
    });
}

function updateOrAddStudent() {
    // 获取表单数据
    var formData = new FormData(document.getElementById('myForm'));
    $.ajax({
        url: 'student',
        type: 'post',
        data: formData,
        contentType: false
    });

}

function checkPage() {
    var appointPage = parseInt($("#appointPage").val());
    var totalPage = parseInt($("#totalPage").text());

    if (appointPage < 0 ) {
        $("#appointPage").val("1");
    }else if(appointPage > totalPage){
        $("#appointPage").val("1");
    }
}

student-table.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
</head>
<body>

<div class="col-sm-8 col-sm-offset-3 col-md-10 col-md-offset-2 main" >

    <h1 class="sub-header">List Student</h1>

    <div class="table-responsive" >
        <table class="table table-striped" th:unless="${#lists.isEmpty(list)}" border="1" cellspacing="0" width="800">
            <thead>
            <tr>
                <th style="text-align:center">学生的编号</th>
                <th style="text-align:center">学生的姓名</th>
                <th style="text-align:center">学生的班级</th>
                <th>删除信息</th>
                <th>修改信息</th>
            </tr>
            </thead>
            <!--   如果没有学生信息,则显示没有学生数据,请添加学生  -->
            <tbody th:if="${#lists.isEmpty(list)}">
            <tr>
                <td th:colspan="5">没有学生数据,请添加学生</td>
            </tr>
            </tbody>
            <!--  如果有学生信息,则遍历展示学生信息   -->
            <tbody th:unless="${#lists.isEmpty(list)}">
            <!--  使用th:each遍历域对象里面的集合    -->
            <tr  th:each="student : ${list}">
                <td th:text="${student.studentId}" align="center">学生的编号</td>
                <td th:text="${student.studentName}" align="center">学生的姓名</td>
                <td th:text="${student.studentClass}" align="center">学生的班级</td>
                <td><a th:onclick="|deleteStudentById(${student.studentId},${pageInfo.currentPage})|" style="cursor: pointer">删除信息</a></td>
                <td><a th:onclick="|toStudentInfoPage(${student.studentId},${pageInfo.currentPage})|" style="cursor: pointer">修改</a></td>
            </tr>
            </tbody>
            <!--   页面导航的超链接    -->
            <tr th:unless="${#lists.isEmpty(list)}">
                <td  colspan="5" align="center"><span id="totalPage" th:text="${pageInfo.totalPage}">共多少页</span>页  第<span th:text="${pageInfo.currentPage}+1">第几页</span></td>
            </tr >
            <tr th:unless="${#lists.isEmpty(list)}">

                <td colspan="5" align="center" >

                    <input type="button" value="跳转"  onclick="showAppointPage()" />
                    <input style="width:70px;" id="appointPage"  th:value="${pageInfo.currentPage+1}" onkeyup="checkPage()" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <input type="button" value="首页"  onclick="getStudentListByPage(0)" />
                    <input th:if="${pageInfo.previousPage != null}" type="button" value="上一页"  th:onclick="|getStudentListByPage(${pageInfo.previousPage})|" />
                    <input th:if="${pageInfo.nextPage != null}" type="button" value="下一页"  th:onclick="|getStudentListByPage(${pageInfo.nextPage})|" />
                    <input type="button" value="尾页"  th:onclick="|getStudentListByPage(${pageInfo.totalPage-1})|" />
                    <br/>
                </td>
            </tr>
        </table>
    </div>
</div>

</body>
</html>

error.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>错误页面</title>

    <script language="javascript" th:inline="javascript">
        //返回登录页面
        function backLogin() {
            window.location.href = "portalServlet";
        }
    </script>

    <style type="text/css">
        .back-button{
            width: 65px;
            color: #fff;
            background-color: #337ab7;
            border-color: #2e6da4;
            -ms-touch-action: manipulation;
            border: 1px solid transparent;
            padding: 6px 12px;
            font-size: 14px;
            line-height: 1.42857143;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <div align="center">
        <img src="image/pange.gif" >
        <h1 th:text="${errorMsg}">显示一个动态的错误信息</h1>
        <input class="back-button" type="submit"  onclick="backLogin()" value="返回"><br/>
    </div>

</body>
</html>

student-insertion.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>学生信息添加页面</title>
    <base th:href="@{/}"/>
    <script type="text/javascript" src="js/jquery-1.8.3.js"></script>
    <link href="/bootstrap-3.4.1-dist/css/bootstrap.css" rel="stylesheet">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script type="text/javascript">
        function check() //onsubmit:return true:表单正常提交,return false表单终止
        {
            var sno=$("#stu_name").val();
            var sname=$("#stu_class").val();
            if(!(sno.length>1&&sno.length<10)){
                alert("填写姓名信息有误!");
                return false;
            }
            if(!(sname.length>2&&sname.length<10)){
                alert("班级信息有误!")
                return false;
            }
            return true;
        }
    </script>
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-12 ">
            <form th:action="@{/student(method='insertStudent')}" method="post" class="form-horizontal" onsubmit="return check()">
                <!-- 表单区域-->
                <fieldset>
                    <!--表单主题-->
                    <legend>填写新增学生信息</legend>
                    <!-- 每一个form-group都可以自定义布局-->
                    <tr ><a th:href="@{/student(method='LoginSuccess')}">返回</a></tr>
                    <div class="form-group">
                        <!-- label表示文字提示标签,可以通过表单的组建的id提示-->

                        <label class="col-md-2 control-label" for="stu_name">学生姓名</label>
                        <div class="col-md-4">
                            <input class="form-control" input type="text" id="stu_name" name="studentName"/>
                        </div>
                    </div>

                    <div class="form-group">
                        <!-- label表示文字提示标签,可以通过表单的组建的id提示-->
                        <label class="col-md-2 control-label" for="stu_class">学生班级</label>
                        <div class="col-md-4">
                            <input class="form-control" type="text" id="stu_class" name="studentClass"/>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-6 col-md-offset-3">
                            <input class="btn btn-primary" type="submit" value="添加"/>
                            <input class="btn btn-warning" type="reset" value="重置"/>
                        </div>
                    </div>
                </fieldset>
            </form>
        </div>
    </div>
</div>
</body>
</html>

student-update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
<div>
    <div style="width: 75%;padding-left: 25%;padding-top: 2%">
        <!-- 表单区域-->
        <form id="myForm">
        <fieldset>
            <legend th:if="${student.studentId != null}">修改学生信息</legend>
            <legend th:if="${student.studentId == null}">添加学生信息</legend>
            <input type="hidden" name="method" value="updateOrAddStudent">
            <input type="hidden" name="currentPage" th:value="${currentPage == null ? -1 : currentPage}" placeholder="Appoint Page">
            <div class="form-group row"  th:if="${student.studentId != null}" >
                <label class="col-md-2 control-label" for="stu_id">学生学号</label>
                <div class="col-md-4">
                    <input class="form-control" readonly="readonly" type="text" id="stu_id" th:value="${student.studentId}" name="studentId" />
                </div>
            </div>
            <div class="form-group row">
                <label class="col-md-2 control-label" for="stu_name">学生姓名</label>
                <div class="col-md-4">
                    <input th:if="${student.studentId != null}" class="form-control" type="text" id="stu_name" th:value="${student.studentName}" name="studentName"/>
                    <input th:if="${student.studentId == null}" class="form-control" type="text" id="stu_name" th:value="${student.studentName}" name="studentName"/>
                </div>
            </div>

            <div class="form-group row">
                <label class="col-md-2 control-label" for="stu_class">学生班级</label>
                <div class="col-md-4">
                    <input th:if="${student.studentId != null}" class="form-control" type="text" id="stu_class" th:value="${student.studentClass}" name="studentClass"/>
                    <input th:if="${student.studentId == null}" class="form-control" type="text" id="stu_class" th:value="${student.studentClass}" name="studentClass"/>
                </div>
            </div>

            <div class="form-group">
                <div class="col-md-6 col-md-offset-3">
                    <input th:if="${student.studentId != null}"class="btn btn-primary" type="submit" value="修改" onclick="updateOrAddStudent()"/>
                    <input th:if="${student.studentId == null}" class="btn btn-primary" type="submit" value="添加" onclick="updateOrAddStudent(-1)"/>
                    <input class="btn btn-warning" type="reset" value="重置"/>
                </div>
            </div>
        </fieldset>
        </form>
    </div>
</div>

</body>
</html>

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

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

相关文章

2023年【司钻(钻井)】及司钻(钻井)作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 司钻&#xff08;钻井&#xff09;是安全生产模拟考试一点通生成的&#xff0c;司钻&#xff08;钻井&#xff09;证模拟考试题库是根据司钻&#xff08;钻井&#xff09;最新版教材汇编出司钻&#xff08;钻井&#…

Tuxera NTFS2023破解版苹果电脑磁盘读写工具

当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。Tuxera 的 Microsoft NTFS for Mac 是一款易于使用的软件&#xff0c;可以在 Mac 上打开、编辑、复制、移动或删…

性能优化:JIT即时编译与AOT提前编译

优质博文&#xff1a;IT-BLOG-CN 一、简介 JIT与AOT的区别&#xff1a; 两种不同的编译方式&#xff0c;主要区别在于是否处于运行时进行编译。 JIT:Just-in-time动态(即时)编译&#xff0c;边运行边编译&#xff1a;在程序运行时&#xff0c;根据算法计算出热点代码&#xf…

CVE-2019-1388 UAC提权实战

1.查看用户权限&#xff1a;guest来宾权限 2.右键-以管理员身份运行&#xff1a; 3.这个时候会弹出UAC&#xff0c;不用管它&#xff0c;点击&#xff1a;显示详细信息 4.然后点击蓝色字体&#xff1a;显示有关此发布者的证书信息 5.来到证书信息这里&#xff0c;点击颁发着…

线程是如何在 6 种状态之间转换的?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 今天我们主要学习线程是如何在 6 种状态之间转换的。 线程的 6 种状态 就像生物从出生到长大、最终死亡的过程一样&#xff0c;线程也有自己的生命周期&#xff0c;在 Java 中线程的生命周期中一共有 6 种状态。 …

揭开 Amazon Bedrock 的神秘面纱 | 基础篇

在 2023 年 4 月&#xff0c;亚马逊云科技曾宣布将 Amazon Bedrock 纳入使用生成式人工智能进行构建的新工具集。Amazon Bedrock 是一项完全托管的服务&#xff0c;提供各种来自领先 AI 公司&#xff08;包括 AI21 Labs、Anthropic、Cohere、Stability AI 和 Amazon 等&#xf…

Python学习第一天-安装Python

文章目录 前言一、下载Python二、执行安装程序三、命令行验证总结 前言 以下榜单来自于TIOBE编程语言流行指数 不多说了&#xff0c;Python天下第一 一、下载Python 从官网下载Python安装程序 二、执行安装程序 找到python-3.12.0-amd64.exe执行&#xff0c;选择Install …

基于Python3的Scapy构造DNS报文

一&#xff1a;DNS协议 DNS&#xff08;Domain Name System&#xff09;协议是计算机网络中的一种基础协议&#xff0c;它用于将域名&#xff08;如www.baidu.com&#xff09;转换为IP地址&#xff08;如192.168.0.1&#xff09;&#xff0c;从而实现计算机之间的通信。 DNS 分…

【Unity地编细节】为什么Unity笔刷在地形上面刷不出来

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

【编解码】解码字符串中的 UNICODE 字符

前言 由于前后端交互中编码的问题&#xff0c;出现了这样的一串字符&#xff1a; {"share_names":["\u4e2d\u6587\u8def\u5f84"]}出现了unicode编码作为字符串内容的情况&#xff0c;直接用json解析的话会报错&#xff0c;所以在json解析前需要先进行转码…

Linux | 深入浅出冯诺依曼

前言 但凡是科班出生的小伙伴多多稍稍应该都听过冯诺依曼体系吧&#xff0c;这似乎已成为入门计算机的必备知识了&#xff0c;本章就带着大家一起去理解冯诺依曼体系&#xff1b; 一、体系构成 冯诺依曼体系主张计算机由五大部件组成&#xff0c;如下所示&#xff1b; 输入设备…

进程(0)——计算机的中的软硬件【Linux】

进程&#xff08;0&#xff09;——计算机的中的软硬件【Linux】 一.硬件&#xff1a;1.1 冯诺依曼结构&#xff1a;1.2 存储金字塔1.2.1输入设备和存储器&#xff1a;1.2.2输出设备和存储器&#xff1a; 二.软件&#xff1a;2.1 操作系统2.1.1 如何理解管理&#xff1a; 博主自…

【Asp.net】Asp.net core中IIS配置注意事项

1、应用地址池设为无托管代码 一、提示&#xff1a;关于IIS上运行ASP.NET Core 站点的“HTTP 500.19”错误 安装dotnet-hosting-3.1.2-win.exe ASP.NET Core 3.1 Runtime (v3.1.2)下载地址&#xff1a; https://download.visualstudio.microsoft.com/download/pr/dd119832-dc4…

visual studio Qt 开发环境中手动添加 Q_OBJECT 导致编译时出错的问题

问题简述 创建项目的时候&#xff0c;已经添加了类文件&#xff0c;前期认为不需要信号槽&#xff0c;就没有添加宏Q_OBJECT,后面项目需要&#xff0c;又加入了宏Q_OBJECT&#xff0c;但是发现只是添加了一个宏Q_OBJECT&#xff0c;除此之外没有改动其它的代码&#xff0c;原本…

AWS Lambda 操作 RDS 示例

实现目标 创建一个 Lambda 接收调用时传入的数据, 写入 RDS 数据库 Post 表存储文章信息. 表结构如下: idtitlecontentcreate_date1我是标题我是正文内容2023-10-21 15:20:00 AWS 资源准备 RDS 控制台创建 MySQL 实例, 不允许 Public access (后面 Lambda 需要通过 VPC 访问…

【Qt进阶之自定义控件】使用QListWidget实现自定义Item效果

目的 Q&#xff1a;如何在Qt库的基础上&#xff0c;实现自定义控件呢&#xff1f; A&#xff1a;根据官方文档回答&#xff0c;就是继承需实现的控件&#xff0c;然后实现自定义功能。 以下是实现QListWidget控件的自定义item。 先看下最终效果是如何&#xff1a; listItem 主…

基于YOLO实现的口罩佩戴检测 - python opemcv 深度学习 计算机竞赛

文章目录 0 前言1 课题介绍2 算法原理2.1 算法简介2.2 网络架构 3 关键代码4 数据集4.1 安装4.2 打开4.3 选择yolo标注格式4.4 打标签4.5 保存 5 训练6 实现效果6.1 pyqt实现简单GUI6.3 视频识别效果6.4 摄像头实时识别 7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xf…

正则表达式,日期选择器时间限制,报错原因

目录 一、正则表达式 1、表达式含义 2、书写表达式 二、时间限制 1、原始日期选择器改造 2、禁止选择未来时间 3、从...到...两个日期选择器的时间限制 三、Uncaught (in promise) Error报错 一、正则表达式 1、表达式含义 &#xff08;1&#xff09;/^([a-zA-Z0-9_.…

2.1.1BFS中的Flood Fill和最短路模型

1.池塘计数 农夫约翰有一片 N ∗ M N∗M N∗M 的矩形土地。 最近&#xff0c;由于降雨的原因&#xff0c;部分土地被水淹没了。 现在用一个字符矩阵来表示他的土地。 每个单元格内&#xff0c;如果包含雨水&#xff0c;则用”W”表示&#xff0c;如果不含雨水&#xff0c;…

Unity 文字显示动画(2)

针对第一版的优化&#xff0c;自动适配文字大小&#xff0c;TextMeshPro可以拓展各种语言。第一版字母类语言效果更好。 using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI;public partial class TextBeat…