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

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

1 编写MVC框架


 服务器启动时,会加载application.properties配置文件,配置文件中有多个类,配置文件是由HandlerMapping来加载。

 HandlerMapping根据配置文件中的每个类,获取到每个类的方法,获取到方法之后再循环遍历这些方法,再找每个带有ResponseBody或ResponseView的方法,再把这些方法都存放在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>


38.png


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>


5.准备二维码的规格对象(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 可选参数
};


通过选择器, 查找到上述的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元试用 (已经领取过的,直接走第三步即可。)

37.png



《3》点击进入阿里云短信官网 , 登陆状态下点击免费开通 (已开通的文字会替换为控制台 , 点击效果一样)

36.png


《4》选择国内消息

35.png


《5》创建短信签名

33.png


34.png


《6》创建短信模板

32.png


《7》创建子账户秘钥


鼠标移至右上角账户名称 选择accesskeys

31.png


选择开始使用子用户AccessKey

输入登陆名称和显示名称, 选择编程访问

30.png


复制得到的accessKeyId和 AccessKeySecret 留待后续使用

29.png


选择创建的子账户 ,点击添加权限

28.png


选择相应的权限, 并点击确定添加

27.png

《8》回到国内短信页面 , 复制审核成功的短信签名名称 以及 短信模板ID。

《9》完成上述步骤后, 已经得到了四个关键性参数

短信签名名称 : 快递e栈

短信模板CODE : SMS_20411…

accessKeyId:LTAI4GKsiFzUmLZ8…

AccessKeySecret: jUhIqqk3wwvhm2T1HOUVbC…

26.png

《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 
);


前台和后台交互的模式大致如下:

25.png


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);
    }
}
相关文章
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
30 1
|
8天前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
63 26
|
20天前
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
31 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
17天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
45 5
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
19天前
|
Java
Java项目中高精度数值计算:为何BigDecimal优于Double
在Java项目开发中,涉及金额计算、面积计算等高精度数值操作时,应选择 `BigDecimal` 而非 `Double`。`BigDecimal` 提供任意精度的小数运算、多种舍入模式和良好的可读性,确保计算结果的准确性和可靠性。例如,在金额计算中,`BigDecimal` 可以精确到小数点后两位,而 `Double` 可能因精度问题导致结果不准确。
|
29天前
|
Java Android开发
Eclipse 创建 Java 项目
Eclipse 创建 Java 项目
39 4
|
26天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
42 0
|
弹性计算 数据可视化 关系型数据库
阿里云服务器部署Java Web项目和连接MySQL数据库全流程
阿里云服务器部署Java Web项目和连接MySQL数据库全流程
6024 0
阿里云服务器部署Java Web项目和连接MySQL数据库全流程
|
4月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本