Java Web基础入门第四十八讲 JDBC实现客户关系管理系统模块

本文详细介绍了使用JDBC技术实现客户关系管理系统的全过程,包括创建MVC架构的Web项目,分层架构的代码编写,涉及domain、DAO、service及web层的开发,涵盖添加、查看、修改和删除客户功能。并提供了数据库表结构、配置文件及项目结构的说明。
摘要由CSDN通过智能技术生成

前言:这是一个使用JDBC技术来实现客户关系管理系统的案例。

创建MVC架构的Web项目

在Eclipse中新创建一个day14_customer项目,导入项目所需要的开发包(jar包),创建项目所需要的包,在Java开发中,架构的层次是以包的形式体现出来的。
在这里插入图片描述
在这里插入图片描述
以上就是根据此项目的实际情况创建的包,可能还需要创建其他的包,这个得根据项目的需求来定了。
接着,为应用创建相应库和表。根据如下数据库表customer的结构,在数据库中创建一张customer表。
在这里插入图片描述
建表SQL语句如下:

create database day14_customer character set utf8 collate utf8_general_ci;
use day14_customer;
create table customer 
(
    id varchar(40) primary key,
    name varchar(40) not null,
    gender varchar(4) not null,
    birthday date,
    cellphone varchar(20),
    email varchar(40),
    preference varchar(255),
    type varchar(100) not null,
    description varchar(255)
);

除此之外,还应在src目录下创建一个db.properties文件,在db.properties中编写MySQL数据库的连接信息,内容如下所示:
在这里插入图片描述
最后,在WEB-INF目录下创建一个jsp目录,jsp目录存放系统的一些受保护(不允许用户直接通过URL地址访问)的jsp页面,用户要想访问这些受保护的jsp页面,一般来说只能通过cn.liayun.web.UI这个包里面的Servlet。但是在这个项目中,我们在cn.liayun.web.UI这个包中并没有创建任何Servlet,关于要想访问这些受保护的jsp页面,后面会详细的介绍到。创建好的项目架构如下图所示:
在这里插入图片描述

分层架构的代码编写

分层架构的代码也是按照【域模型层(domain)】→【数据访问层(dao、dao.impl)】→【业务逻辑层(service、service.impl)】→【表现层(web.controller、web.UI、web.filter、web.listener)】→【工具类(util)】→【测试类(junit.test)】的顺序进行编写的。

开发domain层

在cn.liayun.domain包下创建一个Customer类,该类的具体代码如下:

package cn.liayun.domain;

import java.util.Date;

public class Customer {

	private String id;
	private String name;
	private String gender;
	private Date birthday;
	private String cellphone;
	private String email;
	private String preference;
	private String type;
	private String description;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public String getCellphone() {
		return cellphone;
	}
	public void setCellphone(String cellphone) {
		this.cellphone = cellphone;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getPreference() {
		return preference;
	}
	public void setPreference(String preference) {
		this.preference = preference;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
}

开发数据访问层(dao、dao.impl)

在开发数据访问层时,由于要编写得到MySQL数据库链接和释放资源这些性质的操作,所以应该把它们放在一个JdbcUtils工具类中。在cn.liayun.utils包下创建一个JdbcUtils类,该类的具体代码如下:

package cn.liayun.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
	
	private static Properties config = new Properties();
	
	// 静态代码块只执行一次,因为静态代码块在类加载时执行,类永远只加载一次
	static {
		try {
			config.load(JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"));
			Class.forName(config.getProperty("driver"));
		} catch (Exception e) {
			/*
             * db.properties文件都无法读取,那么整个应用程序就无法连接数据库,
             * 驱动都加载不了,那么整个应用程序都无法正常工作,
             * 所以应该抛一个错误(ExceptionInInitializerError)
             */
			throw new ExceptionInInitializerError(e);
		}
	}

	public static Connection getConnection() throws SQLException {
		return DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
	}
	
	public static void release(Connection conn, Statement st, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;
		}
		
		if (st != null) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st = null;
		}
		
		if (conn != null) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
}

然后,在cn.liayun.dao包下创建一个CustomerDao接口,接口的具体代码如下:

package cn.liayun.dao;

import java.util.List;

import cn.liayun.domain.Customer;

public interface CustomerDao {

	void add(Customer c);

	void update(Customer c);

	void delete(String id);

	Customer find(String id);

	List<Customer> getAll();

}

对于接口中的方法定义,这个只能是根据具体的业务来分析需要定义哪些方法了,但是无论是多么复杂的业务,都离不开基本的CRUD(增删改查)操作,Dao层是直接和数据库交互的,所以Dao层的接口一般都会有增删改查这四种操作的相关方法。
接着应该编写CustomerDao接口的实现类,即CustomerDaoImpl类,其里面一般都会有增删改查这四种操作的相关方法,增删改查时,难免会发生异常,所以在实际开发中,最好每一层都编写一个自定义异常,例如在Dao层(数据访问层)自定义一个DaoException异常类。于是,我们应在cn.liayun.exception包中创建一个DaoException异常类,该类的具体代码如下:

package cn.liayun.exception;

public class DaoException extends RuntimeException {

	public DaoException() {
		// TODO Auto-generated constructor stub
	}

	public DaoException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public DaoException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}

	public DaoException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

}

最后,在cn.liayun.dao.impl包下创建一个CustomerDao接口的实现类——CustomerDaoImpl,该类的具体代码如下:

package cn.liayun.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import cn.liayun.dao.CustomerDao;
import cn.liayun.domain.Customer;
import cn.liayun.exception.DaoException;
import cn.liayun.utils.JdbcUtils;

public class CustomerDaoImpl implements CustomerDao {
	
	@Override
	public void add(Customer c) {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		try {
			conn = JdbcUtils.getConnection();
			String sql = "insert into customer(id,name,gender,birthday,cellphone,email,preference,type,description) values(?,?,?,?,?,?,?,?,?)";
			st = conn.prepareStatement(sql);
			st.setString(1, c.getId());
			st.setString(2, c.getName());
			st.setString(3, c.getGender());
			st.setDate(4, new java.sql.Date(c.getBirthday().getTime()));
			st.setString(5, c.getCellphone());
			st.setString(6, c.getEmail());
			st.setString(7, c.getPreference());
			st.setString(8, c.getType());
			st.setString(9, c.getDescription());
			
			st.executeUpdate();
		} catch (Exception e) {
			throw new DaoException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
	@Override
	public void update(Customer c) {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		try {
			conn = JdbcUtils.getConnection();
			String sql = "update customer set name=?,gender=?,birthday=?,cellphone=?,email=?,preference=?,type=?,description=? where id=?";
			st = conn.prepareStatement(sql);
			st.setString(1, c.getName());
			st.setString(2, c.getGender());
			st.setDate(3, new java.sql.Date(c.getBirthday().getTime()));
			st.setString(4, c.getCellphone());
			st.setString(5, c.getEmail());
			st.setString(6, c.getPreference());
			st.setString(7, c.getType());
			st.setString(8, c.getDescription());
			st.setString(9, c.getId());
			st.executeUpdate();
		} catch (Exception e) {
			throw new DaoException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
	@Override
	public void delete(String id) {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		try {
			conn = JdbcUtils.getConnection();
			String sql = "delete from customer where id=?";
			st = conn.prepareStatement(sql);
			st.setString(1, id);
			st.executeUpdate();
		} catch (Exception e) {
			throw new DaoException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
	@Override
	public Customer find(String id) {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select * from customer where id=?";
			st = conn.prepareStatement(sql);
			st.setString(1, id);
			rs = st.executeQuery();
			if (rs.next()) {
				Customer c = new Customer();
				c.setBirthday(rs.getDate("birthday"));
				c.setCellphone(rs.getString("cellphone"));
				c.setDescription(rs.getString("description"));
				c.setEmail(rs.getString("email"));
				c.setGender(rs.getString("gender"));
				c.setId(rs.getString("id"));
				c.setName(rs.getString("name"));
				c.setPreference(rs.getString("preference"));
				c.setType(rs.getString("type"));
				return c;
			}
			return null;
		} catch (Exception e) {
			throw new DaoException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
	@Override
	public List<Customer> getAll() {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select * from customer";
			st = conn.prepareStatement(sql);
			rs = st.executeQuery();
			List<Customer> list = new ArrayList<Customer>();
			while (rs.next()) {
				Customer c = new Customer();
				c.setBirthday(rs.getDate("birthday"));
				c.setCellphone(rs.getString("cellphone"));
				c.setDescription(rs.getString("description"));
				c.setEmail(rs.getString("email"));
				c.setGender(rs.getString("gender"));
				c.setId(rs.getString("id"));
				c.setName(rs.getString("name"));
				c.setPreference(rs.getString("preference"));
				c.setType(rs.getString("type"));
				list.add(c);
			}
			return list;
		} catch (Exception e) {
			throw new DaoException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
}

照理说,开发完数据访问层,一定要对程序已编写好的部分代码进行测试。但是我们有信心认为以上代码都不会有任何问题,这点自信都没有,搞鬼啊!

开发service层(service层对web层提供所有的业务服务)

在cn.liayun.service包下创建一个BusinessService接口,该接口的具体代码如下:

package cn.liayun.service;

import java.util.List;

import cn.liayun.domain.Customer;

//业务类,统一对Web层提供所有服务
public interface BusinessService {

	void addCustomer(Customer c);

	void updateCustomer(Customer c);

	void deleteCustomer(String id);

	Customer findCustomer(String id);

	List<Customer> getAllCustomer();

}

接着在cn.liayun.service.impl包中编写BusinessService接口的一个实现类——BusinessServiceImpl,该实现类的具体代码如下:

package cn.liayun.service.impl;

import java.util.List;

import cn.liayun.dao.CustomerDao;
import cn.liayun.dao.impl.CustomerDaoImpl;
import cn.liayun.domain.Customer;
import cn.liayun.service.BusinessService;

//此业务层代码很少,所以称为薄薄的业务层
public class BusinessServiceImpl implements BusinessService {
	private CustomerDao dao = new CustomerDaoImpl();
	
	@Override
	public void addCustomer(Customer c) {
		dao.add(c);
	}
	
	@Override
	public void updateCustomer(Customer c) {
		dao.update(c);
	}
	
	@Override
	public void deleteCustomer(String id) {
		dao.delete(id);
	}
	
	@Override
	public Customer findCustomer(String id) {
		return dao.find(id);
	}
	
	@Override
	public List<Customer> getAllCustomer() {
		return dao.getAll();
	}
	
}

同理,开发完业务逻辑层,一定要对程序已编写好的部分代码进行测试,但是我们有信心认为业务逻辑层的代码没有任何问题,所以我们略过测试这一步。

开发web层

在一个项目中,开发web层是最麻烦的,我们一定要有耐心哟!此客户关系管理系统的首页是index.jsp页面,我们是采用分帧的方式来设计的,index.jsp页面的内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>网站首页</title>
</head>
<!-- 分帧(横向)  -->
<frameset rows="20%,*">
	<frame name="head" src="${pageContext.request.contextPath }/head.jsp" />
	<frame name="main" src="" />
</frameset>
</html>

接着我们创建head.jsp页面,head.jsp页面的内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>美美侠客户关系管理系统</title>
</head>
<body style="text-align: center;">
	<h1>美美侠客户关系管理系统</h1>
	<br/>
	                                                            <!-- target="main"的意思是结果显示到name为main的frame中  -->
	<a href="${pageContext.request.contextPath }/AddCustomerServlet" target="main">添加客户</a>
	<a href="${pageContext.request.contextPath }/ListCustomerServlet" target="main">查看客户</a>
</body>
</html>

使用Google Chromer浏览器通过http://localhost:8080/day14_customer/链接访问该客户关系管理系统,显示效果如下:
在这里插入图片描述

开发添加客户的功能

在cn.liayun.utils包下创建一个WebUtils工具类,该工具类的功能就是封装客户端提交的表单数据到Customer对象中,该工具类的具体代码如下:

package cn.liayun.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;

public class WebUtils {
	public static <T> T request2Bean(HttpServletRequest request, Class<T> beanClass) {
		try {
			T bean = beanClass.newInstance();
			//得到request里面的所有数据
			Map<String, String[]> map = request.getParameterMap();
			
			//注册一个日期转换器
			ConvertUtils.register(new Converter() {
				
				@Override
				public <T> T convert(Class<T> type, Object value) {
					if (value == null) {
						return null;
					}
					String str = (String) value;
					if (str.trim().equals("")) {
						return null;
					}
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					try {
						return (T) df.parse(str);
					} catch (ParseException e) {
						throw new RuntimeException(e);
					}
				}
			}, Date.class);
			
			//map{name=liayun,password=123321,birthday=1995-10-01}	bean(name=liayun,password=123321)
			BeanUtils.populate(bean, map);
			return bean;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	// 产生全球唯一的id
	public static String generateID() {
		 // UUID算法根据你系统的网卡的xx地址、CPU、机器的型号等等生成一个128位长的字符串,可以确保是全球唯一的。
		return UUID.randomUUID().toString();
	}
}

当我们访问该客户关系管理系统首页时,要完成添加客户的功能,只须点击添加客户超链接,照理说,我们应该在cn.liayun.web.UI包下创建一个Servlet,诸如这样:

// 给用户提供一个添加客户界面
public class ServletDemo extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ......
                                    // 跳转到一个视图 
        request.getRequestDispatcher("/WEB-INF/jsp/addcustomer.jsp").forward(request, response);
    }

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

}

给用户提供一个添加客户界面,其实还有一种更偷懒的方法。我们大可不必编写如上的Servlet,只须编写一个Servlet,doGet方法用来给用户提供一个添加客户界面,doPost方法用来接收表单的添加客户请求(post),并处理用户的添加请求,这样不是更好嘛!
现在,我们来编写添加客户界面,即addcustomer.jsp,第一次编写该页面的内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>添加用户的视图</title>
</head>
<body style="text-align: center;">
    <br/>
    <form id="form" action="${pageContext.request.contextPath }/AddCustomerServlet" method="post">
    <table border="1" width="50%" align="center">
        <tr>
            <td>客户姓名</td>
            <td>
                <input type="text" name="name">
            </td>
        </tr>
        <tr>
            <td>客户性别</td>
            <td>
                <input type="radio" name="gender" value=""><input type="radio" name="gender" value=""><input type="radio" name="gender" value="人妖">人妖
            </td>
        </tr>
        <tr>
            <td>生日</td>
            <td>
                <input type="text" name="birthday" class="sang_Calender" />
				<script type="text/javascript" src="${pageContext.request.contextPath }/js/datetime.js"></script>
            </td>
        </tr>

        <tr>
            <td>手机</td>
            <td>
                <input type="text" name="cellphone">
            </td>
        </tr>
        <tr>
            <td>邮箱</td>
            <td>
                <input type="text" name="email">
            </td>
        </tr>
        <tr>
            <td>爱好</td>
            <td>
                <input type="checkbox" name="pre" value="唱歌">唱歌
                <input type="checkbox" name="pre" value="跳舞">跳舞
                <input type="checkbox" name="pre" value="逛夜店">逛夜店
            </td>
        </tr>
        <tr>
            <td>客户类型</td>
            <td>
                <input type="radio" name="type" value="VIP客户">VIP客户
                <input type="radio" name="type" value="重点客户">重点客户
                <input type="radio" name="type" value="一般客户">一般客户
            </td>
        </tr>
        <tr>
            <td>客户备注</td>
            <td>
                <textarea rows="5" cols="60" name="description"></textarea>
            </td>
        </tr>
        <tr>
            <td>
                <input type="reset" value="重置">
            </td>
            <td>
                <input type="submit" value="添加客户">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>

由于生日输入框中要输入日期,所以可以从网上随便扒下一个日期时间控件,比如我下载的是一个JS简易版日期时间控件——datetime.js,该日期时间控件的使用方法如下:

  1. 在项目中导入该日期时间控件。
    在这里插入图片描述
    温馨提示:datetime.js所在文件夹应放在WebRoot里,WEB-INF外!
  2. 在生日输入框使用该日期时间控件。
    在这里插入图片描述

思考一下,以上添加客户界面addcustomer.jsp,是我们最终所需要的吗?显然不是,因为客户性别、爱好、客户类型等等都是写死在程序中的,在实际开发中,页面到底输出几个性别,不是在页面中显示的,而是由一个程序维护的,这个程序有几个性别,页面中就输出几个性别。也就是说客户性别、爱好、客户类型等输入选项在数据库里面都有各自对应的表,我们要从数据库里面读取出来并显示在页面中。当然了,我们也不必搞得这么麻烦,只须编写一个Java类来模拟即可。在cn.liayun.utils包中创建一个Globals类,该类的具体代码如下:

package cn.liayun.utils;

public class Globals {
	// 一般用枚举来表示性别
	public static String[] genders = {"男", "女", "人妖"};
	// 在实际开发中,在数据库里面应有一个爱好表,爱好是由一个表来维护的。但在此案例中,不会设计的这么复杂,所以在程序里写死来维护
	public static String[] preferneces = {"唱歌", "跳舞", "桑拿", "打麻将", "看凤姐", "夜生活", "爬山"};
	public static String[] types = {"VIP客户", "重点客户", "普通客户"};
}

接下来就在cn.liayun.web.controller包中创建一个AddCustomerServlet,该Servlet既用来给用户提供一个添加客户界面,又用来接收表单的添加客户请求(post),并处理用户的添加请求。但现在我们只编写该Servlet用来给用户提供一个添加客户界面的代码。

package cn.liayun.web.controller;

import java.io.IOException;
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 cn.liayun.utils.Globals;

@WebServlet("/AddCustomerServlet")
public class AddCustomerServlet extends HttpServlet {
	
	//给用户提供一个添加客户的界面
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("genders", Globals.genders);
		request.setAttribute("preferences", Globals.preferneces);
		request.setAttribute("types", Globals.types);
		
		//跳转到一个视图
		request.getRequestDispatcher("/WEB-INF/jsp/addcustomer.jsp").forward(request, response);
	}

	//处理用户的添加客户请求(post方式)
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		......
	}

}

此时修改添加客户界面addcustomer.jsp。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>添加用户的视图</title>
</head>
<body style="text-align: center;">
	<br/>
	<form id="form" action="${pageContext.request.contextPath }/AddCustomerServlet" method="post" onsubmit="return makepre()">
		<table border="1px" width="50%" align="center">
			<tr>
				<td>客户的姓名</td>
				<td>
					<input type="text" name="name" />
				</td>
			</tr>
			<tr>
				<td>客户的性别</td>
				<td>
					<c:forEach var="gender" items="${genders }">
						<input type="radio" name="gender" value="${gender }" />${gender }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>生日</td>
				<td>
					<input type="text" name="birthday" class="sang_Calender" />
					<script type="text/javascript" src="${pageContext.request.contextPath }/js/datetime.js"></script>
				</td>
			</tr>
			<tr>
				<td>手机号</td>
				<td>
					<input type="text" name="cellphone" />
				</td>
			</tr>
			<tr>
				<td>邮箱</td>
				<td>
					<input type="text" name="email" />
				</td>
			</tr>
			<tr>
				<td>爱好</td>
				<td><!-- pre="唱歌"、pre="夜生活" ---- pre="唱歌,夜生活" -->
					<c:forEach var="p" items="${preferences }">
						<input type="checkbox" name="pre" value="${p }" />${p }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>客户类型</td>
				<td>
					<c:forEach var="type" items="${types }">
						<input type="radio" name="type" value="${type }" />${type }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>客户备注</td>
				<td>
					<textarea rows="5" cols="60" name="description"></textarea>
				</td>
			</tr>
			<tr>
				<td>
					<input type="reset" value="重置" />
				</td>
				<td>
					<input type="submit" value="添加客户" />
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

当用户填写完客户信息,点击添加客户按钮,将表单数据提交到AddCustomerServlet中,在提交爱好这一选项中的数据时,提交的是像这样的数据:

  • pre=”唱歌”
  • pre=”跳舞”

而存到数据库里面的是一串字符串,如:唱歌,跳舞。所以我们应该对提交的爱好数据进行相应地处理,即可在服务器端进行处理,又可在客户端进行处理,我们选择在客户端进行处理,即在addcustomer.jsp页面中添加如下的JavaScript代码:
在这里插入图片描述
接下来,我们在AddCustomerServlet中编写代码,接收表单的添加客户请求(post),并处理用户的添加请求,最终AddCustomerServlet类的完整代码如下:

package cn.liayun.web.controller;

import java.io.IOException;
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 cn.liayun.domain.Customer;
import cn.liayun.service.BusinessService;
import cn.liayun.service.impl.BusinessServiceImpl;
import cn.liayun.utils.Globals;
import cn.liayun.utils.WebUtils;

@WebServlet("/AddCustomerServlet")
public class AddCustomerServlet extends HttpServlet {
	
	//给用户提供一个添加客户的界面
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("genders", Globals.genders);
		request.setAttribute("preferences", Globals.preferneces);
		request.setAttribute("types", Globals.types);
		
		//跳转到一个视图
		request.getRequestDispatcher("/WEB-INF/jsp/addcustomer.jsp").forward(request, response);
	}

	//处理用户的添加客户请求(post方式)
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			request.setCharacterEncoding("UTF-8");
			
			//表单校验,这里我不校验了,默认表单校验通过
			//...
			
			//把表单数据封装到Customer对象中
			Customer c = WebUtils.request2Bean(request, Customer.class);
			c.setId(WebUtils.generateID());
			
			BusinessService service = new BusinessServiceImpl();
			service.addCustomer(c);
			
			request.setAttribute("message", "添加客户成功!!!");
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("message", "添加客户失败!!!");
		}
		request.getRequestDispatcher("message.jsp").forward(request, response);
	}

}

在实际开发中,一定要对表单提交过来的数据进行校验,在我以前的博文
Java Web基础入门第二十九讲 基于Servlet+JSP+JavaBean开发模式的用户登录注册》
中就进行了校验,但在此客户关系管理系统中我们省略这一步。
最后,创建全局消息显示页面message.jsp,内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>全局消息显示</title>
</head>
<body>
	${requestScope.message }
</body>
</html>

测试开发好的添加客户功能。
在这里插入图片描述
到此,开发添加客户的功能算是圆满完成了。

开发查看客户的功能

在cn.liayun.web.controller包下编写ListCustomerServlet,用于得到所有客户并跳转到jsp页面显示,该Servlet的具体代码如下:

package cn.liayun.web.controller;

import java.io.IOException;
import java.util.List;

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 cn.liayun.domain.Customer;
import cn.liayun.service.BusinessService;
import cn.liayun.service.impl.BusinessServiceImpl;

@WebServlet("/ListCustomerServlet")
public class ListCustomerServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//得到所有客户并显示
		try {
			BusinessService service = new BusinessServiceImpl();
			List<Customer> list = service.getAllCustomer();
			request.setAttribute("list", list);
			request.getRequestDispatcher("/WEB-INF/jsp/listcustomer.jsp").forward(request, response);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			request.setAttribute("message", "查看用户失败!!!");
			request.getRequestDispatcher("message.jsp").forward(request, response);
		}
		
	}

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

}

接下来我们创建listcustomer.jsp页面,用于展示所有客户信息。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>列出所有客户</title>
<style type="text/css">
	.even {
		background-color: #FFFF00
	}
	.odd {
		background-color: #FFCCFF
	}
	TR:HOVER {
		background-color: #FF99FF
	}
</style>
</head>
<body style="text-align: center;">
	<table border="1px" width="85%" align="center">
		<tr>
			<td>客户姓名</td>
			<td>性别</td>
			<td>生日</td>
			<td>手机</td>
			<td>邮箱</td>
			<td>爱好</td> 
			<td>类型</td> 
			<td>备注</td>
			<td>操作</td>
		</tr>
		
		<c:forEach var="c" items="${requestScope.list }" varStatus="status">
			<tr class="${status.count % 2 == 0 ? 'even' : 'odd'}">
				<td>${c.name }</td>
				<td>${c.gender }</td>
				<!-- 
					birthday是Date类型的对象,虽然取出来的是Date类型的对象,但el表达式非常聪明,
					它会自动调用此对象的toString()方法,将其变成一个字符串,
					并且它内部会根据你到底是哪个国家和地区而去选用相对应的toString()方法。
				-->
				<td>${c.birthday }</td>
				<td>${c.cellphone }</td>
				<td>${c.email }</td>
				<td>${c.preference }</td>
				<td>${c.type }</td>
				 <td>${c.description }</td>
				<td>
					<a href="#">修改</a>
					<a href="#">删除</a>
				</td>
			</tr>		
		</c:forEach>
	</table>
	<br/>
</body>
</html>

在listcustomer.jsp页面中,我们使用<c:forEach>实现了表格间色显示。更加详细的内容可以参考我的笔记《Java Web基础入门第三十五讲 JSP技术——JSTL标签库之核心标签》中使用<c:forEach>实现表格间色显示。
最后,测试开发好的查看客户功能。
在这里插入图片描述
至此,查看客户功能完成了一小半,还有很多细节没实现。比如有这样一个问题:有些客户的爱好和备注里面的内容会很多,这样显示出来并不好,所以必须截取几个字符,后面加上......来显示,这样才会好一些。现在我们有这样的需求,那该怎么办呢?答案是先去EL函数库里面寻找有没有实现这一需求的函数,结果是发现并没有这样的函数,所以我们可以开发自定义函数,以调用Java类的方法。

  • 在cn.liayun.utils包中创建一个MyEL类,并在MyEL类里编写一个静态处理方法:若一个字符串的长度大于10,则截取其前10个字符,后面加上......并返回。

    package cn.liayun.utils;
    
    public class MyEL {
    	
    	public static String sub(String str) {
    		if (str.length() > 10) {
    			return str.substring(0, 10) + "......";
    		}
    		
    		return str;
    	}
    	
    }
    
  • 在WEB-INF目录下编写标签库描述符(tld)文件,在tld文件中描述自定义函数。
    在这里插入图片描述
    itcast.tld文件的内容如下:

    <?xml version="1.0" encoding="UTF-8" ?>
    
    <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
      version="2.0">
        
      <description>JSTL 1.1 functions library</description>
      <display-name>JSTL functions</display-name>
      <tlib-version>1.1</tlib-version>
      <short-name>fn</short-name>
      <uri>/liayun</uri>
    
      <function>
        <name>sub</name>
        <function-class>cn.liayun.utils.MyEL</function-class>
        <function-signature>java.lang.String sub(java.lang.String)</function-signature>
      </function>
      
    </taglib>
    
  • 在listcustomer.jsp页面中导入和使用自定义函数。

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="/liayun" prefix="liayun" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>列出所有客户</title>
    <style type="text/css">
    	.even {
    		background-color: #FFFF00
    	}
    	.odd {
    		background-color: #FFCCFF
    	}
    	TR:HOVER {
    		background-color: #FF99FF
    	}
    </style>
    </head>
    <body style="text-align: center;">
    	<table border="1px" width="85%" align="center">
    		<tr>
    			<td>客户姓名</td>
    			<td>性别</td>
    			<td>生日</td>
    			<td>手机</td>
    			<td>邮箱</td>
    			<td>爱好</td> 
    			<td>类型</td> 
    			<td>备注</td>
    			<td>操作</td>
    		</tr>
    		
    		<c:forEach var="c" items="${requestScope.list }" varStatus="status">
    			<tr class="${status.count % 2 == 0 ? 'even' : 'odd'}">
    				<td>${c.name }</td>
    				<td>${c.gender }</td>
    				<!-- 
    					birthday是Date类型的对象,虽然取出来的是Date类型的对象,但el表达式非常聪明,
    					它会自动调用此对象的toString()方法,将其变成一个字符串,
    					并且它内部会根据你到底是哪个国家和地区而去选用相对应的toString()方法。
    				-->
    				<td>${c.birthday }</td>
    				<td>${c.cellphone }</td>
    				<td>${c.email }</td>
    				<td>${liayun:sub(c.preference) }</td>
    				<td>${c.type }</td>
    				<td>${liayun:sub(c.description) }</td>
    				<td>
    					<a href="#">修改</a>
    					<a href="#">删除</a>
    				</td>
    			</tr>		
    		</c:forEach>
    	</table>
    	<br/>
    </body>
    </html>
    

再次测试开发好的查看客户功能。
在这里插入图片描述
现在又会产生一个问题,那就是如果数据库表里面有一千万条客户记录,那不是一个页面就要显示一千万条客户信息,这样做显然是非常愚蠢的,所以我们就要实现分页显示的功能了。实现分页显示将在下一讲博客里面详细介绍。

开发修改客户的功能

将listcustomer.jsp页面中操作那一栏中的修改超链接,由下面的
在这里插入图片描述
修改为:
在这里插入图片描述
同开发添加客户的功能一样,我们也只须编写一个Servlet,doGet方法用来给用户提供一个修改客户界面,doPost方法用来接收表单的修改客户请求(post),并处理用户的修改请求。
于是,在cn.liayun.web.controller包中创建一个EditCustomerServlet,该Servlet既用来给用户提供一个修改客户界面,又用来接收表单的修改客户请求(post),并处理用户的修改请求。但是下面我们只编写Servlet用来给用户提供一个修改客户界面的代码。

package cn.liayun.web.controller;

import java.io.IOException;
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 cn.liayun.domain.Customer;
import cn.liayun.service.BusinessService;
import cn.liayun.service.impl.BusinessServiceImpl;
import cn.liayun.utils.Globals;

@WebServlet("/EditCustomerServlet")
public class EditCustomerServlet extends HttpServlet {
	
	//根据ID获取要修改的客户信息
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		BusinessService service = new BusinessServiceImpl();
		Customer c = service.findCustomer(id);
		
		request.setAttribute("c", c);
		request.setAttribute("genders", Globals.genders);
		request.setAttribute("preferences", Globals.preferneces);
		request.setAttribute("types", Globals.types);
		request.getRequestDispatcher("/WEB-INF/jsp/editcustomer.jsp").forward(request, response);
	}

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

}

接着,我们就来编写修改客户界面(editcustomer.jsp),修改客户界面(editcustomer.jsp)和添加客户界面(addcustomer.jsp)非常非常相似,所不同的是增加了数据回显功能。editcustomer.jsp页面的内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改客户信息页面</title>
<script type="text/javascript">
	function makepre() {
		//pre="唱歌"、pre="夜生活" ----> pre="唱歌,夜生活"
		var pres = document.getElementsByName("pre");
		var preference = "";
		for (var i = 0; i < pres.length; i++) {
			var input = pres[i];
			if (input.checked == true) {
				preference = preference + input.value + ",";		
			}
		}
		preference = preference.substr(0, preference.length - 1);
		
		var form =  document.getElementById("form");
		var input = document.createElement("input");
		input.type = "hidden";
		input.name = "preference";
		input.value = preference;
		form.appendChild(input);
		return true;
	}
</script>
</head>
<body style="text-align: center;">
	<br/>
	<form id="form" action="${pageContext.request.contextPath }/EditCustomerServlet" method="post" onsubmit="return makepre()">
		<table border="1px" width="50%" align="center">
			<input type="hidden" name="id" value="${c.id }" />
			<tr>
				<td>客户的姓名</td>
				<td>
					<input type="text" name="name" value="${c.name }" />
				</td>
			</tr>
			<tr>
				<td>客户的性别</td>
				<td>
					<c:forEach var="gender" items="${genders }">
						<input type="radio" name="gender" value="${gender }" ${c.gender==gender ? 'checked' : '' } />${gender }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>生日</td>
				<td>
					<input type="text" name="birthday" class="sang_Calender" value="${c.birthday }" />
					<script type="text/javascript" src="${pageContext.request.contextPath }/js/datetime.js"></script>
				</td>
			</tr>
			<tr>
				<td>手机号</td>
				<td>
					<input type="text" name="cellphone" value="${c.cellphone }" />
				</td>
			</tr>
			<tr>
				<td>邮箱</td>
				<td>
					<input type="text" name="email" value="${c.email }" />
				</td>
			</tr>
			<tr>
				<td>爱好</td>
				<td><!-- pre="唱歌"、pre="夜生活" ---- pre="唱歌,夜生活" -->
					<c:forEach var="p" items="${preferences }">
						<input type="checkbox" name="pre" value="${p }" ${fn:contains(c.preference, p) ? 'checked' : '' } />${p }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>客户类型</td>
				<td>
					<c:forEach var="type" items="${types }">
						<input type="radio" name="type" value="${type }" ${c.type==type ? 'checked' : '' } />${type }
					</c:forEach>
				</td>
			</tr>
			<tr>
				<td>客户备注</td>
				<td>
					<textarea rows="5" cols="60" name="description">${c.description }</textarea>
				</td>
			</tr>
			<tr>
				<td>
					<input type="reset" value="重置" />
				</td>
				<td>
					<input type="submit" value="修改客户" />
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

最后,我们在EditCustomerServlet中编写代码,接收表单的修改客户请求(post),并处理用户的修改请求。最终EditCustomerServlet类的完整代码如下:

package cn.liayun.web.controller;

import java.io.IOException;

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 cn.liayun.domain.Customer;
import cn.liayun.service.BusinessService;
import cn.liayun.service.impl.BusinessServiceImpl;
import cn.liayun.utils.Globals;
import cn.liayun.utils.WebUtils;

@WebServlet("/EditCustomerServlet")
public class EditCustomerServlet extends HttpServlet {
	
	//根据ID获取要修改的客户信息
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		BusinessService service = new BusinessServiceImpl();
		Customer c = service.findCustomer(id);
		
		request.setAttribute("c", c);
		request.setAttribute("genders", Globals.genders);
		request.setAttribute("preferences", Globals.preferneces);
		request.setAttribute("types", Globals.types);
		request.getRequestDispatcher("/WEB-INF/jsp/editcustomer.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		
		//把填写的表单的修改信息封装到Customer对象中
		try {
			Customer c = WebUtils.request2Bean(request, Customer.class);
			BusinessService service = new BusinessServiceImpl();
			service.updateCustomer(c);
			request.setAttribute("message", "更新成功!!!");
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("message", "更新失败!!!");
		}
		request.getRequestDispatcher("/message.jsp").forward(request, response);
	}

}

下面测试开发好的修改客户功能。
在这里插入图片描述
到此,开发修改客户的功能算是圆满完成了。

开发删除客户的功能

将listcustomer.jsp页面中操作那一栏中的删除超链接,由下面的
在这里插入图片描述
修改为:
在这里插入图片描述
温馨提示:有时候JavaScript函数获取不到传递过来的参数,可将传递过来的参数加上单引号('')。
当点击删除超链接时,肯定要给人一个提示,例如弹出一个对话框,告诉人家是否要确定删除吗?不然的话,这个代码就是一个垃圾!所以应在listcustomer.jsp页面中添加如下JavaScript代码:
在这里插入图片描述
这样,最终listcustomer.jsp页面的内容就为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="/liayun" prefix="liayun" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>列出所有客户</title>
<style type="text/css">
	.even {
		background-color: #FFFF00
	}
	.odd {
		background-color: #FFCCFF
	}
	TR:HOVER {
		background-color: #FF99FF
	}
</style>
</head>
<body style="text-align: center;">
	<table border="1px" width="85%" align="center">
		<tr>
			<td>客户姓名</td>
			<td>性别</td>
			<td>生日</td>
			<td>手机</td>
			<td>邮箱</td>
			<td>爱好</td> 
			<td>类型</td> 
			<td>备注</td>
			<td>操作</td>
		</tr>
		
		<c:forEach var="c" items="${requestScope.list }" varStatus="status">
			<tr class="${status.count % 2 == 0 ? 'even' : 'odd'}">
				<td>${c.name }</td>
				<td>${c.gender }</td>
				<!-- 
					birthday是Date类型的对象,虽然取出来的是Date类型的对象,但el表达式非常聪明,
					它会自动调用此对象的toString()方法,将其变成一个字符串,
					并且它内部会根据你到底是哪个国家和地区而去选用相对应的toString()方法。
				-->
				<td>${c.birthday }</td>
				<td>${c.cellphone }</td>
				<td>${c.email }</td>
				<td>${liayun:sub(c.preference) }</td>
				<td>${c.type }</td>
				<td>${liayun:sub(c.description) }</td>
				<td>
					<a href="${pageContext.request.contextPath }/EditCustomerServlet?id=${c.id }">修改</a>
					<a href="javascript:void(0)" onclick="del('${c.id}')">删除</a>
				</td>
			</tr>		
		</c:forEach>
	</table>
	<br/>
	
	<script type="text/javascript">
		function del(id) {
			if (window.confirm("您确定删除吗?")) {
				location.href = '${pageContext.request.contextPath }/DeleteCustomerServlet?id='+id;
			}
		}
	</script>
</body>
</html>

最后,我们在cn.liayun.web.controller包中创建一个DeleteCustomerServlet,用于处理删除客户请求,该Servlet的具体代码如下:

package cn.liayun.web.controller;

import java.io.IOException;
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 cn.liayun.service.BusinessService;
import cn.liayun.service.impl.BusinessServiceImpl;

@WebServlet("/DeleteCustomerServlet")
public class DeleteCustomerServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			String id = request.getParameter("id");
			BusinessService service = new BusinessServiceImpl();
			service.deleteCustomer(id);
			request.setAttribute("message", "删除成功!!!");
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("message", "删除失败!!!");
		}
		request.getRequestDispatcher("/message.jsp").forward(request, response);
	}

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

}

下面测试开发好的删除客户功能。
在这里插入图片描述
到此,开发删除客户的功能算是圆满完成了。

附录(附下载链接)

百度网盘链接:https://pan.baidu.com/s/1EnTJRr-8yX_c2Q8UrFAicQ,提取码:h1gs。

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值