JavaWeb综合项目——快递e栈(后台部分)

本文档详细记录了一个JavaWeb综合项目——快递e栈的后台部分开发过程,涵盖了MVC框架编写、前端补充(包括二维码生成和layui使用)、云短信集成、项目搭建、管理员数据操作、登录交互、流程与表格创建、API设计、DAO接口及实现、Service层编写等各个环节,旨在帮助学习者理解实际后台开发流程。
摘要由CSDN通过智能技术生成

文章目录

写在前面

  Java学习者一个重要的学习分水岭就是JavaWeb技术,这个阶段的学习在已经掌握了Java基础语法之后,并且在学习框架知识之前。
  在我个人看来,完成了JavaWeb知识的学习之后,如果可以自己动手写一个无限接近实际项目的demo的话可以更好的有助于之后阶段的学习。各类框架固然可以极大程度上的简便我们的开发流程,但如果基本的JavaWeb都并不熟练的学习者,可能很难get到框架带来的简便性,反而会被框架中各类的配置劝退,与学习的初衷渐行渐远。
  此外,JavaWeb的练习也可以让我们体验到真正项目的实际后台开发过程,网上的资料也都参差不齐,所以我将花费了一周时间做的demo的步骤一步一步记录下来,并提供全部源码(遇到bug并不可怕,所有调试bug的经历都会成为以后工作学习生涯的宝贵财富)。

  本例实现了但不仅限于以下功能:

后台部分 微信端部分
1.管理员登录
2.管理员退出
3.快件增加
4.快件删除
5.快件修改
6.快件列表查看
7.用户增加
8.用户删除
9.用户删除
10.用户列表查看
11.快递员增加
12.快递员删除
13.快递员修改
14.快递员查询
15.控制台-显示快件区域区分图
16.控制台-显示用户人数
17.控制台-显示快递员人数
18.控制台-显示总快件数
19.控制台-显示等待取件数量
1.用户/快递员登录
2.用户/快递员注册
3.用户-我的取件列表(未取件/已取件)
4.用户-快件取件码展示
5.快递员-扫码取件 6.快递员-取件码取件
7.首页根据快递单号查询快递信息
8.快递员-录入快递
9.快递员历史查询
10.个人中心-昵称显示与修改
11.懒人排行榜

此外,借助微信公众平台实现扫码功能,ngrok实现内网穿透…部分界面如下:

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

注:本例提供所有源码和相应jar文件,可以去我的下载界面下载或者关注我的公众号找我领取。

在这里插入图片描述

1 编写MVC框架

  服务器启动时,会加载application.properties配置文件,配置文件中有多个类,配置文件是由HandlerMapping来加载。
  HandlerMapping根据配置文件中的每个类,获取到每个类的方法,获取到方法之后再循环遍历这些方法,再找每个带有ResponseBodyResponseView的方法,再把这些方法都存放在HandlerMapping中,之后用于处理给用户响应,所以服务器启动之后HandlerMapping中会存一堆方法。
  当用户去请求DispatcherServlet时,首先去HandlerMapping中找有没有处理这个请求的方法,没有的话抛404异常。
  请求servlet的路径是:*.do

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>com.wangjiawei.mvc.DispatcherServlet</servlet-class>
        <!-- 启动的时候加载配置文件 -->
        <init-param>
            <param-name>contentConfigLocation</param-name>
            <param-value>application.properties</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>

在这里插入图片描述

1.1 定义两个注解

package com.wangjiawei.mvc;

import java.lang.annotation.*;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/30 9:56
 * 4 被此注解添加的方法,会被用于处理请求
 * 5 方法返回的内容,会以文字形式返回到客户端
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
   
    String value();
}
package com.wangjiawei.mvc;

import java.lang.annotation.*;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/30 9:56
 * 4 被此注解添加的方法,会被用于处理请求
 * 5 方法返回的内容,会直接重定向
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseView {
   
    String value();
}

再定义枚举类对应上面的两个注解:

package com.wangjiawei.mvc;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/30 10:01
 * 4 响应的类型是文字还是视图
 */
public enum ResponseType {
   
    TEXT,VIEW;
}

1.2 编写映射器 HandlerMapping

package com.wangjiawei.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/30 10:04
 * 4 映射器,包含了大量的网址与方法的对应关系
 */
public class HandlerMapping {
   

    private static Map<String, MVCMapping> data = new HashMap<>();

    public static MVCMapping get(String uri){
   
        return data.get(uri);
    }

    public static void load(InputStream is){
   
        Properties ppt = new Properties();
        try {
   
            ppt.load(is);
        } catch (IOException e) {
   
            e.printStackTrace();
        }
        // 获取配置文件中描述的每个类
        Collection<Object> values = ppt.values();
        for (Object value : values) {
   
            String className = (String)value;
            try {
   
                // 加载配置文件中描述的每个类(用于处理请求的类)
                Class c = Class.forName(className);
                // 创建类的对象
                Object obj = c.getConstructor().newInstance();
                // 获取类的所有方法
                Method[] methods = c.getMethods();
                for (Method method : methods) {
   
                    Annotation[] as = method.getAnnotations();
                    if (as != null){
   
                        for (Annotation annotation : as){
   
                            if (annotation instanceof ResponseBody){
   
                                // 此方法用于返回字符串给客户端
                                MVCMapping mvcMapping = new MVCMapping(obj, method, ResponseType.TEXT);
                                Object o = data.put(((ResponseBody) annotation).value(), mvcMapping);
                                if (o != null){
   
                                    // 存在了重复的请求地址
                                    throw new RuntimeException("请求地址重复" + ((ResponseBody) annotation).value());
                                }
                            }else if(annotation instanceof ResponseView){
   
                                // 此方法用于返回界面给客户端
                                MVCMapping mvcMapping = new MVCMapping(obj, method, ResponseType.VIEW);
                                Object o = data.put(((ResponseView) annotation).value(), mvcMapping);
                                if (o != null){
   
                                    // 存在了重复的请求地址
                                    throw new RuntimeException("请求地址重复" + ((ResponseView) annotation).value());
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
   
                e.printStackTrace();
            }
        }
    }

    /**
     * 映射对象,每一个对象封装了一个方法,用于处理请求
     */
    public static class MVCMapping{
   
        private Object obj;
        private Method method;
        private ResponseType type;

        public MVCMapping() {
   
        }

        public MVCMapping(Object obj, Method method, ResponseType type) {
   
            this.obj = obj;
            this.method = method;
            this.type = type;
        }

        public Object getObj() {
   
            return obj;
        }

        public void setObj(Object obj) {
   
            this.obj = obj;
        }

        public Method getMethod() {
   
            return method;
        }

        public void setMethod(Method method) {
   
            this.method = method;
        }

        public ResponseType getType() {
   
            return type;
        }

        public void setType(ResponseType type) {
   
            this.type = type;
        }
    }
}

1.3 定义分发Servlet

package com.wangjiawei.mvc;

import javax.servlet.ServletConfig;
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.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/29 21:22
 * 4
 */
public class DispatcherServlet extends HttpServlet {
   

    @Override
    public void init(ServletConfig config) throws ServletException {
   
        String path = config.getInitParameter("contentConfigLocation");
        InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
        HandlerMapping.load(is);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
        // 获取用户请求的uri
        String uri = req.getRequestURI();
        HandlerMapping.MVCMapping mvcMapping = HandlerMapping.get(uri);

        if (mvcMapping == null){
   
            resp.sendError(404, "MVC:映射地址不存在" + uri);
            return;
        }

        Object obj = mvcMapping.getObj();
        Method method = mvcMapping.getMethod();
        Object result = null;
        try {
   
            result = method.invoke(obj, req, resp);
        } catch (IllegalAccessException e) {
   
            e.printStackTrace();
        } catch (InvocationTargetException e) {
   
            e.printStackTrace();
        }
        switch (mvcMapping.getType()){
   
            case TEXT:
                resp.getWriter().write((String) result);
                break;
            case VIEW:
                resp.sendRedirect((String) result);
                break;
            default:
                break;
        }

    }
}

1.4 测试类

package com.wangjiawei.test;

import com.sun.deploy.net.HttpResponse;
import com.wangjiawei.mvc.ResponseBody;
import com.wangjiawei.mvc.ResponseView;

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

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/9/30 11:08
 * 4
 */
public class UserController {
   

    @ResponseBody("/login.do")
    public String login(HttpServletRequest request, HttpServletResponse response){
   
        return "login success";
    }

    @ResponseView("/reg.do")
    public String reg(HttpServletRequest request, HttpServletResponse response){
   
        return "success.jsp";
    }
}

2 前端补充

2.1 二维码生成

步骤:

  1. 引入Jquery.js文件
  2. 引入jquery.qrcode.js文件
  3. 引入支持中文的编码js文件 (utf.js)
  4. 在网页中编写一个div 用于显示二维码
 <div id="div1"></div>
  1. 准备二维码的规格对象(JSON)
var config  = {
   
    width:数字,//值是number类型, 表示的单位是px  必须传递
    height:数字,//值是number类型, 表示的单位是px  必须传递 
    text:"内容",//text就表示二维码中存储的数据  必须传递
    correctLevel:数字,//取值为0|1|2|3 表示二维码的纠错级别0:L/1:M/2:Q/3:H ,默认0  可选参数
    background:"#rrggbb",//默认白色, 表示二维码的后景颜色 可选参数
    foreground:"#rrggbb",//默认黑色, 表示二维码的前景颜色 可选参数
    render:"绘制模式"//取值:table/canvas , 默认table 可选参数
};
  1. 通过选择器, 查找到上述的div ,得到Jquery对象, 通过jquery对象的qrcode函数生成二维码
$("#div1").qrcode(config);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>二维码生成</title>
    <script src="js/jquery2.1.4.js"></script>
    <script src="js/jquery.qrcode.js"></script>
    <script src="js/utf.js"></script>
</head>
<body>
    <div id="qrcode"></div>
    <script>
        var config = {
    
            width:200,
            height:200,
            text:"欢迎关注【N小王日记】"
        };
        $("#qrcode").qrcode(config);
    </script>
</body>
</html>

2.2 layui

layui官网

2.2.1 布局部分

与BootStrap很像,就是展示一些界面效果。

2.2.2 弹出层

步骤:

  1. 下载layer , 并将解压后的layer文件夹 移动到项目中
  2. 引入jquery.js
  3. 引入layer.js

layer - msg函数

用于弹出信息提示框

格式1

layer.msg("文本");

格式2 抖动显示

 layer.msg("文本",function(){
   
        //弹窗结束后会执行
    });

layer - load函数
格式1
  弹出loading:

var index = layer.load(数字0-2); 
// 参数表示 loading的图表
//loading窗口在弹出时, 不允许进行操作.

关闭loading:

layer.close(index);

格式2
  超时自动关闭的loading

var index = layer.load(数字0-2,{
   time:毫秒数字})
//在指定的毫秒后 ,如果没有使用layer.close关闭, 则自动关闭

layer - msg函数(load效果)
格式:
  弹出的格式:

var index = layer.msg("文本",{
   icon:16,shade:0.01})
//因为是msg函数, 所以此窗口会自动消失

关闭的格式:

layer.close(index);

layer - alert函数 信息提示窗
格式:

layer.alert("文本内容",{
   icon:图片编号});
//图片编号: 0-16之间 

layer - tips函数 提示层
格式:

layer.tips("文本内容","选择器",{
   tipsMore:true,tips:数字});

参数:

  1. 参数: tipsMore : 是否允许同时存在多个弹出的tips
  2. 参数: tips : 取值为数字1-4 , 分别表示弹出在元素的 上/右/下/左 . 默认弹出在右边

layer 所有弹出层的关闭

layer.closeAll();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jquery2.1.4.js"></script>
    <script src="layer/layer.js"></script>
    
    <script>
        function msgTest() {
    
            // layer.msg("提示的文字");
            layer.msg("提示的文字", function () {
    
                // 窗口关系时执行,和上面的区别还有会添加一个抖动
            });
        }
        
        function loadTest() {
    
            // 返回弹出层的id
            var windowId = layer.load(0);  // 0 - 16的数字,每一个代表不同效果
            // 通过窗口id关闭窗口
            setTimeout(function () {
    
                layer.close(windowId);
            }, 2000);
        }

        function msg_loadTest() {
    
            // icon不同的值对应不同的图标
            layer.msg("提示的文字", {
    icon:16, shade:0.01});
        }
        
        function alertTest() {
    
            layer.alert("文字内容", {
    icon : 10});
        }

        function tipsTest() {
    
            // tipsMore表示
            layer.tips("这里有秘密", "#s1", {
    tipsMore:true, tips:2});
        }
    </script>
</head>
<body>
    <button onclick="msgTest()">msg函数(*)</button><br>
    <button onclick="loadTest()">load函数(*)</button><br>
    <button onclick="msg_loadTest()">load函数(load效果)</button><br>
    <button onclick="alertTest()">alert函数</button><br>
    <button onclick="tipsTest()">tips函数</button><br>
    <p>
        锄禾日<span id="s1">当午</span>,汗滴禾下土
    </p>
</body>
</html>

3 云短信使用

关键点:

  1. 在阿里云的sms控制台 创建签名
  2. 在阿里云的sms控制台 创建短信模板code值
  3. 在阿里云的RAM访问控制中心,新建一个用户 accessKeyId
  4. 在阿里云的RAM访问控制中心,新建一个用户 AccessKeySecret

《1》点击进入阿里云免费试用 , 然后登陆账号。
《2》 如图选择短信0元试用 (已经领取过的,直接走第三步即可。)

在这里插入图片描述
《3》点击进入阿里云短信官网 , 登陆状态下点击免费开通 (已开通的文字会替换为控制台 , 点击效果一样)
在这里插入图片描述
《4》选择国内消息

在这里插入图片描述
《5》创建短信签名
在这里插入图片描述
在这里插入图片描述
《6》创建短信模板
在这里插入图片描述
《7》创建子账户秘钥

  • 鼠标移至右上角账户名称 选择accesskeys
    在这里插入图片描述
  • 选择开始使用子用户AccessKey
  • 输入登陆名称和显示名称, 选择编程访问
    在这里插入图片描述
    复制得到的accessKeyId和 AccessKeySecret 留待后续使用
    在这里插入图片描述
  • 选择创建的子账户 ,点击添加权限
    在这里插入图片描述
  • 选择相应的权限, 并点击确定添加
    在这里插入图片描述
    《8》回到国内短信页面 , 复制审核成功的短信签名名称 以及 短信模板ID
    《9》完成上述步骤后, 已经得到了四个关键性参数
    短信签名名称 : 快递e栈
    短信模板CODE : SMS_20411…
    accessKeyId:LTAI4GKsiFzUmLZ8…
    AccessKeySecret: jUhIqqk3wwvhm2T1HOUVbC…
    在这里插入图片描述
    《9》下载jar文件 , 并引入到项目中

《10》将上述参数, 复制到如下代码中。 并通过JSON方式顺序填充每一个短信模板中到参数

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.google.gson.Gson;

import java.util.HashMap;
import java.util.Random;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/1 10:42
 * 4
 */
public class SMSDemo {
   
    public static void main(String[] args) {
   
        Random r = new Random();
        int num = r.nextInt(900000) + 100000;
        send("18373110779", num + "");
    }

    public static boolean send(String phoneNumber,String code) {
   
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI4GKsiFzUmLZ8Qnx1Sfza", "jUhIqqk3wwvhm2T1HOUVbCmIOWNE0O");
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", phoneNumber);
        request.putQueryParameter("SignName", "快递e栈");
        request.putQueryParameter("TemplateCode", "SMS_204115757");
        request.putQueryParameter("TemplateParam", "{\"code\":\""+ code +"\"}");
        try {
   
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            String json = response.getData();
            Gson g = new Gson();
            HashMap result = g.fromJson(json, HashMap.class);
            if("OK".equals(result.get("Message"))) {
   
                return true;
            }else{
   
                System.out.println("短信发送失败,原因:"+result.get("Message"));
            }
        } catch (ServerException e) {
   
            e.printStackTrace();
        } catch (ClientException e) {
   
            e.printStackTrace();
        }
        return false;
    }
}

4 项目搭建

4.1 Druid

见下载资源

4.2 MVC

见 编写MVC框架 部分

4.3 时间格式化工具类

package com.wangjiawei.util;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/1 11:30
 * 4
 */
public class DateFormatUtil {
   

    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String format(Date date){
   
        return format.format(date);
    }
}

4.4 前后端用于通信的消息类

package com.wangjiawei.bean;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/1 12:36
 * 4
 */
public class Message {
   

    // {status:0, result:"", data:{}}

    /**
     * 状态码 0表示成功,-1表示失败
     */
    private int status;

    /**
     * 消息内容
    */
    private String result;

    /**
    消息所携带的一组数据
     */
    private Object data;

    public Message() {
   
    }

    public Message(int status) {
   
        this.status = status;
    }

    public Message(String result) {
   
        this.result = result;
    }

    public Message(int status, String result, Object data) {
   
        this.status = status;
        this.result = result;
        this.data = data;
    }

    public String getResult() {
   
        return result;
    }

    public void setResult(String result) {
   
        this.result = result;
    }

    public Object getData() {
   
        return data;
    }

    public void setData(Object data) {
   
        this.data = data;
    }

    public int getStatus() {
   
        return status;
    }

    public void setStatus(int status) {
   
        this.status = status;
    }
}

4.5 随机数工具类

用于生成取件码

package com.wangjiawei.util;

import java.util.Random;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/4 14:09
 * 4
 */
public class RandomUtil {
   

    private static Random r = new Random();
    public static int getCode(){
   
        return r.nextInt(900000) + 100000;
    }

}

4.6 Json操作类

package com.wangjiawei.util;

import com.google.gson.Gson;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/1 13:50
 * 4
 */
public class JSONUtil {
   

    private static Gson g = new Gson();

    public static String toJSON(Object obj){
   
        return g.toJson(obj);
    }
}

5 管理员数据操作部分

后台管理前端页面模板:放在web.admin文件夹下

CREATE TABLE eadmin ( 
    id INT PRIMARY KEY auto_increment, 
    username VARCHAR ( 32 ), 
    PASSWORD VARCHAR ( 32 ), 
    loginip VARCHAR ( 32 ), 
    logintime datetime, 
    createtime datetime 
);

前台和后台交互的模式大致如下:
在这里插入图片描述
dao层接口:

package com.wangjiawei.dao;

import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/2 9:20
 * 4   用于定义eadmin表的操作规范
 */
public interface BaseAdminDao {
   

    /**
     * 根据用户名,更新登录时间和登录ip
     * @param username
     */
    void updateLoginTime(String username, Date date, String ip);

    /**
     * 管理员根据账号密码登录
     * @param username
     * @param password
     * @return 登录结果 true:登录成功
     */
    boolean login(String username, String password);
}

dao层的实现类:

package com.wangjiawei.dao.imp;

import com.wangjiawei.dao.BaseAdminDao;
import com.wangjiawei.util.DruidUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/2 9:26
 * 4
 */
public class AdminDaoMysql implements BaseAdminDao {
   
    private static final String SQL_UPDATE_LOGIN_TIME = "UPDATE EADMIN SET LOGINTIME = ?, LOGINIP = ? WHERE USERNAME = ?";
    private static final String SQL_LOGIN = "SELECT ID FROM EADMIN WHERE USERNAME = ? AND PASSWORD = ?";

    /**
     * 根据用户名,更新登录时间和登录ip
     *
     * @param username
     * @param date
     * @param ip
     */
    @Override
    public void updateLoginTime(String username, Date date, String ip) {
   
        Connection connection = DruidUtil.getConnection();
        PreparedStatement state = null;
        try {
   
            state = connection.prepareStatement(SQL_UPDATE_LOGIN_TIME);
            state.setDate(1, new java.sql.Date(date.getTime()));
            state.setString(2, ip);
            state.setString(3, username);
            state.executeUpdate();
        } catch (SQLException throwables) {
   
            throwables.printStackTrace();
        }finally {
   
            DruidUtil.close(connection,state,null);
        }
    }

    /**
     * 管理员根据账号密码登录
     *
     * @param username
     * @param password
     * @return 登录结果 true:登录成功
     */
    @Override
    public boolean login(String username, String password) {
   
        Connection connection = DruidUtil.getConnection();
        PreparedStatement state = null;
        ResultSet resultSet = null;
        try {
   
            state = connection.prepareStatement(SQL_LOGIN);
            state.setString(1,username);
            state.setString(2,password);
            resultSet = state.executeQuery();
            // 如果能查出来则有,返回true
            return resultSet.next();
        } catch (SQLException throwables) {
   
            throwables.printStackTrace();
        }finally {
   
            DruidUtil.close(connection,state,null);
        }
        return false;
    }
}

service层:

package com.wangjiawei.service;

import com.wangjiawei.dao.BaseAdminDao;
import com.wangjiawei.dao.imp.AdminDaoMysql;

import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/2 9:52
 * 4
 */
public class AdminService {
   

    private static BaseAdminDao dao = new AdminDaoMysql();

    /**
     * 更新登陆时间与ip
     * @param username
     * @param date
     * @param ip
     */
    public static void updateLoginTimeAndIp(String username, Date date, String ip){
   
        dao.updateLoginTime(username, date, ip);
    }

    /**
     * 登录
     * @param username
     * @param password
     * @return true:成功,false:失败
     */
    public static boolean login(String username, String password){
   
        return dao.login(username, password);
    }
}

6 管理员登录前后端交互

6.1 登录

前端页面login.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="assets/css/layui.css">
    <link rel="stylesheet" href="assets/css/login.css">
    <link rel="icon" href="/favicon.ico">
    <title>快递e栈管理后台</title>
</head>
<body class="login-wrap">
    <div class="login-container">
       <h3>快递e栈后台管理</h3>
        <form class="login-form" action="index.html">
            <div class="input-group">
                <input type="text" id="username" class="input-field">
                <label for="username" class="input-label">
                    <span class="label-title">用户名</span>
                </label>
            </div>
            <div class="input-group">
                <input type="password" id="password" class="input-field">
                <label for="password" class="input-label">
                    <span class="label-title">密码</span>
                </label>
            </div>
            <button type="button" class="login-button">登录<i class="ai ai-enter"></i></button>
        </form>
    </div>
</body>
<script src="assets/layui.js"></script>
<script src="js/index.js" data-main="login"></script>
<script src="js/login.js" data-main="login"></script>
<script src="../qrcode/jquery2.1.4.js"></script>
<script src="../layer/layer.js"></script>
<script>
    $(function () {
    
        $(".login-button").click(function () {
    
            var username = $("#username").val();
            var password = $("#password").val();

            if(username == null || password == null || username == "" || password == ""){
    
                alert("用户名或密码不能为空");
           }else{
    
                // 先转圈(使用layer弹出load,提示加载中)
                var windowId = layer.load();
                // ajax与服务器交互
                $.post("login.do", {
    username:username, password:password}, function (data) {
    
                    // 关闭load窗口
                    layer.close(windowId);
                    // 将服务器回复的结果进行显示
                    layer.msg(data.result);
                    if (data.status == 0){
    
                        // 跳转到主页
                        location.assign("index.html");
                    }

                }, "JSON");
            }
        });
    })
</script>
</html>

编写管理员登录的controller:

package com.wangjiawei.controller;

import com.wangjiawei.bean.Message;
import com.wangjiawei.mvc.ResponseBody;
import com.wangjiawei.service.AdminService;
import com.wangjiawei.util.JSONUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/2 10:28
 * 4
 */
public class AdminController {
   

    @ResponseBody("/admin/login.do")
    public String login(HttpServletRequest request, HttpServletResponse response){
   
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        boolean result = AdminService.login(username, password);
        // 准备不同的返回数据
        Message msg = null;
        if (result){
   
            // {status:0, result:"登录成功"}
            msg = new Message(0, "登录成功");
            // 登录时间和ip的更新
            Date date = new Date();
            String ip = request.getRemoteAddr();
            AdminService.updateLoginTimeAndIp(username, date, ip);
        }else {
   
            // {status:-1, result:"登录失败"}
            msg = new Message(-1, "登录失败");
        }
        String json = JSONUtil.toJSON(msg);
        return json;
    }
}

为了不显示乱码,定义过滤器设置编码:

package com.wangjiawei.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 2 * @Author: 小王同学
 * 3 * @Date: 2020/10/2 10:50
 * 4
 */
@WebFilter("*.do")
public class CharSetFilter implements Filter {
   
    public void destroy() {
   
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
   
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/json;charset=utf-8");
        resp.setCharacterEncoding("utf-8");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
   

    }

}

6.2 显示当前用户姓名(以主页面为例)

AdminController中添加获取姓名方法:

@ResponseBody("/admin/getName.do")
public String getName(HttpServletRequest request, HttpServletResponse response){
   
    String userName = UserUtil.getUserName(request.getSession());
    Message msg = new Message();
    msg.setStatus(0);
    msg.setResult("查询成功");
    msg.setData(userName);
    String json = JSONUtil.toJSON(msg);
    return json;
}

index.html部分:

$.post("/admin/getName.do",{
   },function (data) {
   
    // {
   
    //     "status": 0,
    //     "result": "查询成功",
    //     "data": "admin"
    // }
    $("#adminName").text(data.data);
});

6.3 退出登录(以主页面为例)

AdminController中添加退出登录方法:

@ResponseBody("/admin/logout.do")
public String logout(HttpServletRequest request, HttpServletResponse response){
   
    HttpSession session = request.getSession();
    session.removeAttribute("adminUserName");
    Message msg = new Message();
    msg.setStatus(0);
    msg.setResult("退出成功");
    String json = JSONUtil.toJSON(msg);
    return json;
}

index.html完整代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="assets/css/layui.css">
    <link rel="stylesheet" href="assets/css/admin.css">
    <link rel="icon" href="/favicon.ico">
    <title>快递e栈管理后台</title>
</head>
<body class="layui-layout-body">
    <div class="layui-layout layui-layout-admin">
        <div class="layui-header custom-header">
            
            <ul class="layui-nav layui-layout-left">
                <li class="layui-nav-item slide-sidebar" lay-unselect>
                    <a href="javascript:;" class="icon-font"><i class="ai ai-menufold"></i></a>
                </li>
            </ul>

            <ul class="layui-nav layui-layout-right">
                <li class="layui-nav-item">
                    <a><span id="adminName">aaaaaaa</span></a>
                    <dl class="layui-nav-child">
                        <dd><a href="#">帮助中心</a></dd>
                        <dd><a id="logout" href="login.html">退出</a></dd>
                    </dl>
                </li>
            </ul>
        </div>

        <div class="layui-side custom-admin">
            <div class="layui-side-scroll">

                <div class="custom-logo">
                    <img src="assets/images/logo.gif" alt=""/>
                    <h1>快递e栈</h1>
                </div>
                <ul id="Nav" class="layui-nav layui-nav-tree">
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon">&#xe68e;</i>
                            <em>主页</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a href="views/console.html"><i class="layui-icon">&#xe665;</i> 控制台</a></dd>
                        </dl>
                    </li>
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon">&#xe664;</i>
                            <em>快递员管理</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a href="views/courier/list.html"><i class="layui-icon">&#xe60a;</i> 快递员列表</a></dd>
                            <dd><a href="views/courier/add.html"><i class="layui-icon">&#xe654;</i> 快递员录入</a></dd>
                            <dd><a href="views/courier/update.html"><i class="layui-icon">&#xe642;</i> 快递员修改</a></dd>
                            <dd><a href="views/courier/delete.html"><i class="layui-icon">&#xe640;</i> 快递员删除</a></dd>
                        </dl>
                    </li>
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon">&#xe857;</i>
                            <em>快件管理</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a href="views/express/list.html"><i class="layui-icon">&#xe60a;</i> 快件列表</a></dd>
                            <dd><a href="views/express/add.html"><i class="layui-icon">&#xe654;</i> 快件录入</a></dd>
                            <dd><a href="views/express/update.html"><i class="layui-icon">&#xe642;</i> 快件修改</a></dd>
                            <dd><a href="views/express/delete.html"><i class="layui-icon">&#xe640;</i> 快件删除</a></dd>
                        </dl>
                    </li>
                     <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon">&#xe770;</i>
                            <em>用户管理</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a href="views/user/list.html"><i class="layui-icon">&#xe60a;</i> 用户列表</a></dd>
                            <dd><a href="views/user/add.html"><i class="layui-icon">&#xe654;</i> 用户增加</a></dd>
                            <dd><a href="views/user/update.html"><i class="layui-icon">&#xe642;</i> 用户修改</a></dd>
                            <dd><a href="views/user/delete.html"><i class="layui-icon">&#xe640;</i> 用户删除</a></dd>
                        </dl>
                    </li>
                </ul>

            </div>
        </div>

        <div class="layui-body">
             <div class="layui-tab app-container" lay-allowClose="true" lay-filter="tabs">
                <ul id="appTabs" class="layui-tab-title custom-tab"></ul>
                <div id="appTabPage" class="layui-tab-content"></div>
            </div>
        </div>

        <div class="layui-footer">
            <p>©2020 <a href="http://www.itdage.com/" target="_blank">王家尉版权声明</a></p>
        </div>

        <div class="mobile-mask"></div>
    </div>
    <script src="assets/layui.js"></script>
    <script src="js/index.js" data-main="home"></script>
    <script src="/qrcode/jquery2.1.4.js"></script>
    <script>
        $(function () {
    
            $.post("/admin/getName.do",{
    },function (data) {
    
                // {
    
                //     "status": 0,
                //     "result": "查询成功",
                //     "data": "admin"
                // }
                $("#adminName").text(data.data);
            });

            $("#logout").click(function () {
    
                var windowId = layer.load();
                $.post("/admin/logout.do",{
    },function (data) {
    
                    layer.msg(data.result);
                    layer.close(windowId);
                    location.href = "/admin/login.html";
                })
            });
        });
    </script>

</body>
</html>

7 流程与快递表格创建

7.1 编写流程

  1. 管理员登录
  2. 快递管理
  • 快递列表
    • 分页查询的列表
  • 新增快递
    • 用户输入内容,后台接收参数,向数据库存储
  • 删除快递
    • 用户输入快递单号查询快递信息
    • 浏览快递信息的最后,可以点击删除按钮,删除快递
  • 修改快递
    • 用户输入快递单号查询到快递信息
    • 浏览(可修改)快递信息的最后,可以点击确认按钮,确认修改快递
  1. 用户管理
  • 用户列表
  • 新增用户
  • 删除用户
  • 修改用户
  1. 快递员管理
  • 快递员列表
  • 新增快递员
  • 删除快递员
  • 修改快递员
  1. 控制台显示

7.2 编写步骤

  • 创建数据库表格
  • 编写DAO
  • 编写service
  • 编写controller
  • 前后端交互
    • 前端发起ajax→DispatcherServlet→Controller→Service→DAO→数据库

前后端交互标准流程:

  • 前端发起ajax
$("按钮选择器").click(function(){
   
            //1.    先使用layer,弹出load(提示加载中...)
            var windowId = layer.load();
            //2.    ajax与服务器交互
            $.post("服务器地址",参数JSON,function(data){
   
                //3.    关闭load窗口
                layer.close(windowId);
                //4.    将服务器回复的结果进行显示
                layer.msg(data.result);
            },"JSON");
        });
  • 编写Controller,用于处理ajax的请求
    • 在Controller中调用service处理
    • 处理完毕, 根据service返回的结果,给ajax返回

7.3 数据库创建

7.3.1 快递

CREATE TABLE Express(
	id int PRIMARY KEY auto_increment,
	number VARCHAR
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王曾是少年

如果对你有帮助,欢迎支持我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值