用户管理大任务的完结

x33g5p2x  于2022-02-07 转载在 其他  
字(16.8k)|赞(0)|评价(0)|浏览(310)

今天完成了所有的项目代码,从0到1的开发,从项目的构建到最后docker-compose的部署发布,中途有很多心酸,也有很多进步,无数个头疼的夜晚,无数细节的小Bug,今日写此文来回顾一下这个充实的礼拜!分享一下我的办公室:(爱了CSDN)

一:项目的完成截图:

二:项目整体实现的代码以及艰辛:

1:登录功能的实现:

(1):首先,我们就直接进入建好了初始的javaweb项目然后写好数据库的连接文件:db.properties,以及其内容:

# 连接MYSQL数据库的配置文件 注:等号的前后不要写空格
# 驱动名
jdbcName=com.mysql.cj.jdbc.Driver
# 数据库连接 ( db_lezijie_note是数据库的名称)
dbUrl=jdbc:mysql://localhost:3306/manager?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
# 数据库的连接账号 (账号基本上都是root)
dbName=root
# 数据库的连接密码 (每个人的数据库密码可能不一致,需要修改)
dbPwd=root

(2):写好基本的util包里面的数据库连接类:DBUtil:

package com.ftz.Demo.util;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @author ${范涛之}
 * @Description
 * @create 2021-12-08 10:08
 */
public class DBUtil {
    /**
     * 得到配置文件对象
     */
    private  static Properties properties = new Properties();

    static {
        try {
            //加载配置文件(输入流)
            InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
            // 通过load()方法将数日六的内容加载到配置文件对象中
            properties.load(in);
            // 通过配置文件对象的getProperty()方法获取驱动名,拿到驱动名之后加载驱动
            Class.forName(properties.getProperty("jdbcName"));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取数据库连接
     * @return
     */
    public  static Connection getConnection(){
        Connection connection = null;

        try {
            //得到数据库链接的相关性息
            String dbUrl = properties.getProperty("dbUrl");
            String dbName = properties.getProperty("dbName");
            String dbPwd = properties.getProperty("dbPwd");

            connection = DriverManager.getConnection(dbUrl,dbName,dbPwd);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return  connection;

    }

    /**
     * 关闭资源
     * @param resultSet
     * @param preparedStatement
     * @param connection
     */
    public  static  void close(ResultSet resultSet,
                               PreparedStatement preparedStatement,
                               Connection connection){
        //判断资源对象如果不为空则关闭

        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    }
}

(3)写好基本的po层实体类,vo层信息回显类:

package com.ftz.Demo.po;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String sex;
    private String phone;
    private String idcard;
    private String address;
    private String workplace;
    private Integer age;
    private String emile;
    private Integer credits;
    private String money;
    private String coupon;
    private String name;
    private String headimg;
    private String type;
    public void id(Integer userId) {
        this.id = userId;
    }

}
package com.ftz.Demo.vo;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
public class ResultInfo<T> {
    private Integer code; //状态码
    private String msg; // 提示信息
    private T result; //  返回的对象(字符串、JavaBean、集合、Map等)
}

(4)登陆界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="static/login.css">
    <title>登录</title>
</head>
<body>

<div class="box">
    <form action="user">
        <h4>用户登录中心</h4>
        <input type="hidden" name="actionName" value="login"/>
        <div class="acc">
            <input type="text" placeholder="请输入用户名" name="username">
            <input type="password" placeholder="请输入密码" name="password">
<%--            <span id="msg" style="color: red;font-size: 12px;">状态信息:${resultInfo.msg}</span><br/><br/>--%>
            <span><input id="" name="validate" type="text" placeholder="请输入验证码" style="font-size: 15px"/>  <img id="img" src="validateCode" οnclick="changeImg()"/>    </span>

        </div>

        <button type="submit" class="btn fff">登陆</button>
        <div class="fn">
            <label for="check"><input id="check" type="checkbox"><span><span></span></span>记住我</label>
            <a href="forget.jsp" class="ccc">忘记密码</a>
        </div>
        <div class="reg">
            <p>还没有账号?
                <a href="sign.jsp" class="ccc">立即注册</a>
            </p>
        </div>
    </form>
</div>

<script type="text/javascript">
    function changeImg() {
        document.getElementById("img").src="validateCode?n="+Math.random();
    }
</script>

</body>

</html>

--------------------------分割线---------------------------------------

突然感觉一个一个去写会很累,我直接写自己的心得哇,我在做这个项目遇到的问题以及需要注意的点:

首先就是在上传头像的时候遇到的问题:我们其实是分两步走的,就是编辑界面的那个上传头像和更改信息表面上是在同一个界面中其实是分开的两个表单,然后就是图片是需要使用二进制流的形式发送的但是其他的普通信息倘若使用二进制流会造成传输失败,这里就需要用到com.jspsmart.upload.SmartUpload这个包,然后他会将传输的request请求封装起来!所以在下面调用这个请求的时候记得一定要使用封装过后的!!!:

还有就是前端验证码的回显:直接在图片的url那里写后端的代码就好,这里我用了一个封装起来的组件:validateCode

package com.ftz.Demo.controller;

import cn.dsna.util.images.ValidateCode;

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

@WebServlet(name = "ValidateCodeServlet", value = "/validateCode")
public class ValidateCodeServlet extends HttpServlet {

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

        System.out.println("现在进入这个生成验证码的类");
        //告诉客户端不使用缓存
        response.setHeader("param", "no-cache");
        response.setHeader("cache-control", "no-cache");
        response.setIntHeader("expires", 0);
        // 1 创建验证码
        ValidateCode validateCode = new ValidateCode(100, 30, 4, 30);
        // 2 将验证码存储到Session
        HttpSession session = request.getSession();
        session.setAttribute("validateCode", validateCode.getCode());
        // 3 将验证码以图片的形式发给浏览器
        validateCode.write(response.getOutputStream());

    }
}

然后就是忘记密码的邮箱发送:在安全连接那里需要先写成false:然后就是验证码的传输一定记得去使用Session存储验证码的值!!!

/**
     * 用户忘记密码
     */
    public   void  userSignByCode(HttpServletRequest request,HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("UTF-8");
        //设置服务器端以UTF-8编码进行输出
        response.setCharacterEncoding("UTF-8");
        //设置浏览器以UTF-8编码进行接收,解决中文乱码问题
        response.setContentType("text/html;charset=UTF-8");
        String emile = request.getParameter("emile");
        System.out.println("这是controller接受到前端发送过来的邮箱");
        // 2. 调用Service层的方法,返回ResultInfo对象
        ResultInfo resultInfo =userService.userSign(emile);
        System.out.println("我查到了这个用户");
        // 如果有这个用户
        if (resultInfo.getCode()==1){
            System.out.println("我是controller层我数据库中有使用这个邮箱的用户");
            EmileCode emileCode = new EmileCode();
            String str = emileCode.achieveCode();
            System.out.println("这是生成的验证码"+str);
            emileCode.sendAuthCodeEmail(emile,str);
            System.out.println("邮件发送成功");
            HttpSession session = request.getSession();
            session.setAttribute("str",str);
            response.sendRedirect("code.jsp");
        }else {   // 如果没有这个用户
            System.out.println("我是controller层数据库中没有使用这个邮箱的用户");
            request.getRequestDispatcher("false.jsp").forward(request,response);
        }
    }

这里逻辑梳理一下就是,显示点击一开始的忘记密码那个按钮就会进入第一个界面:

然后这里输入你的邮箱账号后就会后端进入调用忘记密码的方法,也就是上面发的代码那里,然后这里先通过serice检测一下有没有使用这个邮箱的用户:

在controller调用一下判断是否有这个用户,判断完成后,调用发送邮箱验证码的方法生成验证码:

package com.ftz.Demo.util;
import org.apache.commons.mail.SimpleEmail;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class EmileCode {

    public  String achieveCode() {  //由于数字 1 、 0 和字母 O 、l 有时分不清楚,所以,没有数字 1 、 0
        String[] beforeShuffle= new String[] { "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F",
                "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a",
                "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
                "w", "x", "y", "z" };
        List list = Arrays.asList(beforeShuffle);//将数组转换为集合
        Collections.shuffle(list);  //打乱集合顺序
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)); //将集合转化为字符串
        }
        return sb.toString().substring(3, 8);  //截取字符串第4到8
    }
    //发送邮件代码
    public  String sendAuthCodeEmail(String email, String authCode) {
        try {
            SimpleEmail mail = new SimpleEmail();
            mail.setHostName("smtp.qq.com");//发送邮件的服务器
            mail.setAuthentication("1668714992@qq.com","sgpodxtsxiefecaj");//刚刚记录的授权码,是开启SMTP的密码
            mail.setFrom("1668714992@qq.com","来自火星");  //发送邮件的邮箱和发件人
            mail.setSSLOnConnect(false); //使用安全链接
            mail.addTo(email);//接收的邮箱
            //System.out.println("email"+email);
            mail.setSubject("注册验证码");//设置邮件的主题
            mail.setMsg("尊敬的用户:你好!\n 注册验证码为:" + authCode+"\n"+"     (有效期为一分钟)");//设置邮件的内容
            mail.send();//发送
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  authCode;
    }

}

上面就是生成验证码的代码,然后将验证码存在session里面,然后跳转到下一个界面:下一个界面就是输入验证码的地方,用户在输入收到的验证码后提交进入后端:

package com.ftz.Demo.controller;

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

@WebServlet("/code")
public class CodeController extends HttpServlet {


    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     codeSign(req,resp);
    }

    public void   codeSign(HttpServletRequest request, HttpServletResponse response) throws IOException {
        UserController userController = new UserController();
        String code = request.getParameter("code");
        System.out.println("前端接收到的用户输入的验证码是是"+code);
        HttpSession session = request.getSession();
        String str = (String) session.getAttribute("str");
        System.out.println("从session中拿到的值是"+str);

        if ( str.equals(code)){
            System.out.println("登陆成功");
            response.sendRedirect("success.jsp");
        }else{
            System.out.println("验证码输入错误!");
            response.sendRedirect("false.jsp");
        }
    }
}

在这里就会从Session里面取到验证码的值,然后做判断,判断成功后进入用户列表界面!

分页查询的实现:

首先是在Dao层写两个查询页数的方法:

/**
     * 计算页的总数
     */
    public  int getPage() throws SQLException {
        int recordCount=0,t1=0,t2=0;
        Connection connection = null;
        PreparedStatement pr = null;
        ResultSet rs = null;
        connection = DBUtil.getConnection();
        String sql = "select count(*) from user";
        pr = connection.prepareStatement(sql);
        rs = pr.executeQuery();
        rs.next();
        //获取全部数据数量
        recordCount=rs.getInt(1);
        // t1是页数,t2是每页的显示数据条数
        t1=recordCount%5;
        t2=recordCount/5;
        if(t1 != 0){
            t2=t2+1;
        }
        return t2;
    }

    /**
     * 查询指定页的数据
     * @param pageNo
     * @return
     */
    public List<User> listUser(int pageNo) throws SQLException {
        Connection connection = null;
        PreparedStatement pstmt=null;
        ResultSet resultSet=null;
        List<User> list=new ArrayList<User>();
        int pageSize=5;
        int page=(pageNo-1)*5;
        connection = DBUtil.getConnection();
        String sql="select * from user order by id limit ?,?";
        pstmt = connection.prepareStatement(sql);
        pstmt.setInt(1, page);
        pstmt.setInt(2, pageSize);
        resultSet=pstmt.executeQuery();
        while(resultSet.next()){
            User user = new User();
            user.setId(Integer.valueOf(resultSet.getString(1)));
            user.setUsername(resultSet.getString(2));
            user.setPassword(resultSet.getString(3));
            user.setHeadimg(resultSet.getString(15));
            user.setName(resultSet.getString(14));
            user.setEmile(resultSet.getString(10));
            user.setPhone(resultSet.getString(6));
            user.setWorkplace(resultSet.getString(9));
            user.setAddress(resultSet.getString("address"));
            user.setWorkplace(resultSet.getString("workplace"));
            user.setType(resultSet.getString(16));
            list.add(user);
        }
        return  list;
    }

然后记住这里的resultSet.next下面的赋值要根据自己的实体类去赋值,然后去写控制层:

package com.ftz.Demo.controller;
import com.ftz.Demo.dao.UserDao;
import com.ftz.Demo.po.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/ListUser")
public class ListUser extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        int pageNo = 1;
        UserDao userdao=new UserDao();
        List<User> lists=new ArrayList<User>();
        String pageno=request.getParameter("pageNos");
        if(pageno != null){
            pageNo=Integer.parseInt(pageno);
        }
        try {
            lists=userdao.listUser(pageNo);
            int recordCount=userdao.getPage();
            request.setAttribute("recordCount", userdao.getPage());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        request.setAttribute("listss", lists);
        request.setAttribute("pageNos", pageNo);
        request.getRequestDispatcher("user.jsp").forward(request, response);
    }

}

然后就会跳转到前端user.jsp界面

user.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java"  isELIgnored="false"  %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>用户界面</title>
	<link rel="stylesheet" href="static/css/style.css">
</head>
<body>
<div class="subbox">
	<table>
		<thead>
		<tr>
			<th>头像</th>
			<th>名字</th>
			<th>邮箱</th>
			<th>手机号码</th>
			<th>工作单位</th>
			<th>操作</th>

		</tr>
		</thead>
		<tbody>
		<c:forEach items="${listss}" var="user">
		<tr>
			<td><img src="/img/${user.id}.jpg"></td>
			<td><span class="name">${user.name}</span></td>
			<td><span class="email">${user.emile}</span></td>
			<td><span class="date">${user.phone}</span></td>
			<td><span class="option is-orange">${user.workplace}</span></td>
			<td><span class="comment"><a href='UserEditById?id=${user.id}'>编辑</a>  <a href='UserClod?username=${user.username}'>冻结</a></span></td>
		</tr>
		</c:forEach>
		</tbody>
	</table>
	<br>
	<br>
	<div align="center">
	<c:if test="${pageNos>1 }">
		<a href="ListUser?pageNos=1" >首页</a>
		<a href="ListUser?pageNos=${pageNos-1 }">上一页</a>
	</c:if>
	<c:if test="${pageNos <recordCount }">
		<a href="ListUser?pageNos=${pageNos+1 }">下一页</a>
		<a href="ListUser?pageNos=${recordCount }">末页</a>
	</c:if>
	<form action="ListUser">
		<h4 align="center">共${recordCount}页 &nbsp
			<input type="text" value="${pageNos}" name="pageNos" size="1">页
			<input type="submit" value="到达">
		</h4>
	</form>
	</div>
</div>

</body>
</html>

最后就是docker的部署了,编写docker-conpose文件,其实这就是一个很简单的javaweb配mysql项目,所以只需要添加这两个依赖:

version: "3.1"
services:
  mysql:
    restart: always
    image: daocloud.io/library/mysql:5.7.4
    container_name: mysql
    ports: 
    - 3306:3306
    environment: 
    - MYSQL_ROOT_PASSWORD=root
    - TZ=Asia/Shanghai
    volumes:
    - ./mysql/mysql_data:/var/lib/mysql
  tomcat:
    restart: always
    image: daocloud.io/library/tomcat:8.5.15-jre8
    container_name: tomcat
    ports:
    - 8080:8080
    environment: 
    - TZ=Asia/Shanghai
    volumes:
    - ./tomcat/webapps:/usr/local/tomcat/webapps
    - ./tomcat/logs:/usr/local/tomcat/logs

在里面设置了挂载,然后就OK喽只需要将打包好滴war包放到Webapps里面就好!,哦对这里说一下当我们遇到额外都jar包怎么使用IDEA打包,也就是不在POM中使用Maven管理的包:

在Pom里面添加这个,写好jar包的路径:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
                <compilerArguments>
                    <extdirs>${basedir}/src/main/webapp/WEB-INF/lib</extdirs>
                </compilerArguments>
            </configuration>
        </plugin>
    </plugins>
</build>

然后就可以打包了!

准备开启新的阶段了!!再见,servlet!

相关文章

目录