『Java课设』JavaSwing+MySQL实现学生成绩管理系统

news2024/11/30 0:38:14

👨‍🎓作者简介:一位喜欢写作,计科专业大三菜鸟

🏡个人主页:starry陆离

如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

『Java课设』JavaSwing+MySQL实现学生成绩管理系统

  • 前言
  • 1.开发工具
  • 2.项目包结构
  • 3.数据库表
  • 4.JDBC数据库连接类
  • 5.管理员登录界面(部分)
  • 6.管理员增删改查页面(部分)
  • 8.项目演示
    • 8.1登录
    • 8.2查询学生
    • 8.3增加数据
    • 8.4修改数据
    • 8.5删除数据

前言

不久前整理资料,看到了自己大二刚学完Java为了写的课设项目敲的一个课设雏形(后来课设没有用这个),因为是个半成品一共就一个界面而且很烂,但不舍得删,发出来留作纪念吧。

1.开发工具

Eclipse

Java JDK1.8

MySQL精简版

SQLyog

mysql-connector-java-5.1.41 MySQL :: Download Connector/J

sqljdbc

image-20220708104107581

2.项目包结构

image-20220708111948227

3.数据库表

数据库名:studentgrade

数据库表:manager、student

image-20220708104234777

image-20220708104259940

4.JDBC数据库连接类

连接mysql和sqlserver的方法有一点点不一样,这里笔者的机器没有sqlserver就不维护sqlserver的了,读者有需要可自行解决

//连接mysql5.7
	private static final String USER = "***";//数据库用户名,一般是root
	private static final String PWD = "******";//数据库密码
//	private static final String URL="jdbc:mysql://localhost:3306/studentgrade";
//	private static final String DRIVER="com.mysql.jdbc.Driver"; //mysql5.7
	//如果用的是mysql8.0,
	private static final String DRIVER="com.mysql.cj.jdbc.Driver";
	private static final String URL= "jdbc:mysql://localhost:3306/studentgrade?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true"; 
	

5.管理员登录界面(部分)

image-20220708111525699

package view;

import handler.LoginHandler;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;
/**
 * 管理员登录界面
 * 也是项目运行的起始界面
 * @author starry
 * 测试用户名:lx
 * 密码:lx0411
 */
public class LoginView extends JFrame {

    JLabel titleNameLabel=new JLabel("学生成绩管理系统",JLabel.CENTER);
    
    SpringLayout spLayout=new SpringLayout();
    JPanel centerPanel=new JPanel(spLayout);
    
    JLabel userNameLabel=new JLabel("用户名:");
    JLabel userPwdLabel=new JLabel("登录密码:");

    JTextField nameTxd=new JTextField();
    JPasswordField pwdFiled=new  JPasswordField();

    JButton loginBtn=new JButton("登录");
    JButton resetBtn=new JButton("重置");

    //声明桌面系统托盘SystemTray
    SystemTray systemTray;
    TrayIcon trayIcon;
    LoginHandler loginHandler;

    public LoginView(){

        super("学生成绩管理系统");

        loginHandler=new LoginHandler(this);
        //获取内容面板
        Container contentPane =getContentPane();
        //设置标题的字体,格式,大小
        titleNameLabel.setFont(new Font("华文行楷",Font.PLAIN,40));
        titleNameLabel.setPreferredSize(new Dimension(0,80));
        //设置中间各个组件的字体,大小,格式
        Font centerFont=new Font("华文行楷",Font.PLAIN,20);
        userNameLabel.setFont(centerFont);
        nameTxd.setPreferredSize(new Dimension(200,30));
        userPwdLabel.setFont(centerFont);
        pwdFiled.setPreferredSize(new Dimension(200,30));
        loginBtn.setFont(centerFont);
        resetBtn.setFont(centerFont);

        contentPane.setBackground(Color.pink);

        //把组件加入到面板上
        centerPanel.add(userNameLabel);
        centerPanel.add(userPwdLabel);
        centerPanel.add(nameTxd);
        centerPanel.add(pwdFiled);
        centerPanel.add(loginBtn);
        centerPanel.add(resetBtn);

        loginBtn.addActionListener(loginHandler);//增加登录按键的事件监听
        loginBtn.addKeyListener(loginHandler);//增加键盘按键监听事件
        resetBtn.addActionListener(loginHandler);//增加重置按键的事件监听

        contentPane.add(titleNameLabel,BorderLayout.NORTH);
        contentPane.add(centerPanel,BorderLayout.CENTER);

        //设置中间组件的位置,弹簧布局
        layoutCenter();

        //判断当前系统是否支持系统托盘
        if(SystemTray.isSupported()){
            systemTray=SystemTray.getSystemTray();//初始化系统托盘
            URL imgUrl = LoginView.class.getClassLoader().getResource("LoginView.jpg");
            trayIcon=new TrayIcon(new ImageIcon(imgUrl).getImage());//初始化托盘图标
            trayIcon.setImageAutoSize(true);//托盘图标可以自动缩放大小
            try {
                systemTray.add(trayIcon);//将托盘图标加入到系统托盘组件中,并抛出异常
            } catch (AWTException e) {
                e.printStackTrace();
            }
            //创建一个事件响应,最小化时销毁资源
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowIconified(WindowEvent e) {
                    LoginView.this.dispose();
                }
            });

            //托盘事件监听(鼠标单击一次托盘,窗口将会正常显示)
            trayIcon.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    int clickCont=e.getClickCount();
                    if(clickCont==1){
                        LoginView.this.setExtendedState(JFrame.NORMAL);
                    }
                    LoginView.this.setVisible(true);
                }
            });
        }
        //设置loginBtn为默认按钮,按下回车键时默认响应loginBtn的键盘响应
        getRootPane().setDefaultButton(loginBtn);

        //设置窗口图片
        URL imgUrl=LoginView.class.getClassLoader().getResource("LoginView.jpg");
        setIconImage(new ImageIcon(imgUrl).getImage());
        //设置窗口基本参数
        setSize(600,400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);
        setVisible(true);
    }

    private void layoutCenter() {
        //获取组件的宽度Spring.width(组件名)用户名和用户名文本框组件
        Spring titleLabelWidth=Spring.width(userNameLabel);
        Spring titleTextWidth=Spring.width(nameTxd);
        Spring spaceWidth=Spring.constant(20);//userNameLabel和nameTxd的间距
        Spring totalWidth=Spring.sum(Spring.sum(titleLabelWidth,titleTextWidth),spaceWidth);
        int offSetX=totalWidth.getValue()/2;

         /*
        SpringLayout:布局管理器
        SpringLayout.Constraints:使用弹簧布局的容器里面的组件的布局约束,每个组件对应一个
        Spring:能够进行四则运算的整数
         */
        /*
        窗口相当于一个左顶角为原点的第四象限的坐标轴

         */
        //1.设置好用户名标签的位置(约束)
        SpringLayout.Constraints titleLabelCon=spLayout.getConstraints(userNameLabel);
        //用户名标签userNameLabel的西边参考centerPanel组件水平中心点方向左偏移offSetX的距离
        spLayout.putConstraint(SpringLayout.WEST,userNameLabel,-offSetX,SpringLayout.HORIZONTAL_CENTER,centerPanel);
        //设置用户名标签的垂直标签
        spLayout.putConstraint(SpringLayout.NORTH,userNameLabel,20,SpringLayout.NORTH,centerPanel);
        //or使用setY()设置垂直偏移量
        // titleLabelCon.setY(Spring.constant(50));//垂直偏移量

        //2.设置用户名文本框nameTxd的位置(约束)
        spLayout.putConstraint(SpringLayout.WEST,nameTxd,20,SpringLayout.EAST,userNameLabel);
        spLayout.putConstraint(SpringLayout.NORTH,nameTxd,0,SpringLayout.NORTH,userNameLabel);

        //3.设置密码标签userPwdLabel的位置
        spLayout.putConstraint(SpringLayout.NORTH,userPwdLabel,20,SpringLayout.SOUTH,userNameLabel);
        spLayout.putConstraint(SpringLayout.EAST,userPwdLabel,0,SpringLayout.EAST,userNameLabel);

        //4.设置密码文本框pwdFiled的位置(约束)
        spLayout.putConstraint(SpringLayout.WEST,pwdFiled,20,SpringLayout.EAST,userPwdLabel);
        spLayout.putConstraint(SpringLayout.NORTH,pwdFiled,0,SpringLayout.NORTH,userPwdLabel);

        //5.设置登录按钮loginBtn的位置
        spLayout.putConstraint(SpringLayout.EAST,loginBtn,-20,SpringLayout.HORIZONTAL_CENTER,centerPanel);
        spLayout.putConstraint(SpringLayout.NORTH,loginBtn,50,SpringLayout.SOUTH,pwdFiled);

        //6.设置重置按钮resetBtn的位置
        spLayout.putConstraint(SpringLayout.WEST,resetBtn,20,SpringLayout.HORIZONTAL_CENTER,centerPanel);
        spLayout.putConstraint(SpringLayout.NORTH,resetBtn,50,SpringLayout.SOUTH,pwdFiled);
    }

    public static void main(String[] args){
        new LoginView();
    }


    public JTextField getNameTxd() {
        return nameTxd;
    }

    public JPasswordField getPwdFiled() {
        return pwdFiled;
    }
}

6.管理员增删改查页面(部分)

image-20220708111607388

package view;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.net.URL;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import ext.MainViewTable;
import ext.MainViewTableModel;
import handler.AdminMainHandler;
import req.StudentRequest;
import res.TableDTO;
import service.StudentService;
import service.StudentServiceImpl;
import util.DimensionUtil;
/**
 * 管理员管理学生的主界面
 * 可在此实现增删改查
 * @author starry
 *
 */
public class MainView extends JFrame{
	
	
	public String lastPressKey;
	
	JPanel northPanel=new JPanel(new FlowLayout(FlowLayout.LEFT));//JPanel默认流布局,组件居左
	public JButton btnAdd=new JButton("增加");
	public JButton updataBtn=new JButton("修改");
	public JButton delBtn=new JButton("删除");
	public JButton btnSave = new JButton("保存");
	JTextField searchTxt=new JTextField(15);
	JButton searchBtn=new JButton("查询");
	
	//搜索框与搜索按钮
    public JTextField searchField = new JTextField();
	
	JPanel southPanel=new JPanel(new FlowLayout(FlowLayout.RIGHT));//组件居右
	JButton preBtn=new JButton("上一页");
	JButton nextBtn =new JButton("下一页");
	
	
	//创建一个MainViewTable对象
  	public MainViewTable mianViewTable=new MainViewTable();
  	public MainViewTableModel mainViewTableModel;
	//声明一个MainHandler对象
	AdminMainHandler adminMainHandler;
	
	//
	private int pageNow=1;//默认显示第一页
	private int pageSize=10;//默认每页显示十条记录
	//构造方法
	public MainView() {
		
		super("主界面-学生成绩管理系统");
		Container contentPane=getContentPane();
		
		//创建一个MainHandler对象
		adminMainHandler = new AdminMainHandler(this);
		
		//放置北边的组件
		layoutNorth(contentPane);
		//放置中间的组件
		layoutCenter(contentPane);
		//放置南边的组件
		layoutSouth(contentPane);
		//基础设置
	    init();
	}

	private void layoutCenter(Container contentPane) {
		
		//调用数据库数据,创建一个StudentService和StudentRequest实例
		//获取从数据库中查询到的data与totalCount
		StudentService studentService=new StudentServiceImpl();
		StudentRequest request=new StudentRequest();
		request.setPageNow(pageNow);
		request.setPageSize(pageSize);
		request.setSearchKey(searchTxt.getText().trim());
		TableDTO tableDTO = studentService.retrieveStudents(request);
		Vector<Vector<Object>> data = tableDTO.getData();
		showPreNext(tableDTO.getTotalCount());
		
		
        //自定义的MainViewTableModel
		mainViewTableModel=MainViewTableModel.assembleModel(data);
		//将Table与TableModel关联
		mianViewTable.setModel(mainViewTableModel);
		//设置渲染方式
		mianViewTable.renderRule();
		
		
		
		 JScrollPane jScrollPane = new JScrollPane(mianViewTable);
		 contentPane.add(jScrollPane,BorderLayout.CENTER);
	}



	private void layoutSouth(Container contentPane) {
		
		//增加按钮事件监听
		preBtn.addActionListener(adminMainHandler);
		nextBtn.addActionListener(adminMainHandler);
		
		southPanel.add(preBtn);
		southPanel.add(nextBtn);
		contentPane.add(southPanel,BorderLayout.SOUTH);
	}
	
	/*
	 * 设置上一页与下一页按钮是否可见
	 */
	private void showPreNext(int totalCount) {
		if(pageNow==1) {
			preBtn.setVisible(false);
		}else {
			preBtn.setVisible(true);
		}
		//总共的页数
		int pageCount=0;
		if(totalCount%pageSize==0) {
			pageCount=totalCount/pageSize;
		}else {
			pageCount=totalCount/pageSize+1;
		}
		if(pageCount==pageNow) {
			nextBtn.setVisible(false);
		}else {
			nextBtn.setVisible(true);
		}
	}

	private void layoutNorth(Container contentPane) {
		
		//增加按钮事件监听
		btnAdd.addActionListener(adminMainHandler);
		btnSave.addActionListener(adminMainHandler);
		updataBtn.addActionListener(adminMainHandler);
		delBtn.addActionListener(adminMainHandler);
		searchBtn.addActionListener(adminMainHandler);

		
		northPanel.add(btnAdd);
		northPanel.add(btnSave);
		northPanel.add(updataBtn);
		northPanel.add(delBtn);
		northPanel.add(searchTxt);
		northPanel.add(searchBtn);
		btnAdd.setVisible(true);
		btnSave.setVisible(false);
		contentPane.add(northPanel,BorderLayout.NORTH);
	}
	
	private void init() {
		//设置窗口图片
        URL imgUrl=LoginView.class.getClassLoader().getResource("LoginView.jpg");
        setIconImage(new ImageIcon(imgUrl).getImage());
        //设置窗口基本参数
        setBounds(DimensionUtil.getBounds());
        //设置窗体完全充满整个屏幕
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(true);
        setVisible(true);
	}


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
	}
	
	public void setPageNow(int pageNow) {
		this.pageNow = pageNow;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getPageNow() {
		return pageNow;
	}

	
	public void reloadTable() {
		
		/*
		 *调用数据库数据,创建一个StudentService和StudentRequest实例
		 *获取从数据库中查询到的data与totalCount
		 *查询完后要更新Model的数据
		 */
		StudentService studentService=new StudentServiceImpl();
		StudentRequest request=new StudentRequest();
		request.setPageNow(pageNow);
		request.setPageSize(pageSize);
		request.setSearchKey(searchTxt.getText().trim());
		TableDTO tableDTO = studentService.retrieveStudents(request);
		Vector<Vector<Object>> data = tableDTO.getData();
		
		
		// 更新调用updataModel实现更新Model
		MainViewTableModel.uptadaModel(data);
		// 设置渲染方式
		mianViewTable.renderRule();
		// 调用上一页与下一页按钮是否可见
		showPreNext(tableDTO.getTotalCount());
	}
	

}

8.项目演示

8.1登录

grade1

8.2查询学生

grade2

8.3增加数据

grade3

8.4修改数据

grade4

8.5删除数据

grade5

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

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

相关文章

SparkMlib 之随机森林及其案例

文章目录什么是随机森林&#xff1f;随机森林的优缺点随机森林示例——鸢尾花分类什么是随机森林&#xff1f; 随机森林算法是机器学习、计算机视觉等领域内应用极为广泛的一个算法&#xff0c;它不仅可以用来做分类&#xff0c;也可用来做回归即预测&#xff0c;随机森林机由…

RabbitMQ之可靠性分析

在使用任何消息中间件的过程中&#xff0c;难免会出现消息丢失等异常情况&#xff0c;这个时候就需要有一个良好的机制来跟踪记录消息的过程&#xff08;轨迹溯源&#xff09;&#xff0c;帮助我们排查问题。在RabbitMQ 中可以使用Firehose 功能来实现消息追踪&#xff0c;Fire…

艾美捷MTT细胞增殖检测试剂盒结果示例引用文献

艾美捷MTT细胞增殖检测试剂盒测定原理&#xff1a; 该试剂盒提供了比色形式测量和监测细胞增殖&#xff0c;含有足够的试剂用于评估在96孔板中进行960次测定或在24孔板中进行192次测定。细胞可以被镀&#xff0c;然后用影响增殖的化合物或药剂。然后用增殖试剂检测细胞&#x…

3.矩阵计算及导数基础

1. 梯度 将导数拓展到向量。 1. 标量对向量求导 x是列向量&#xff0c;y是标量&#xff0c;求导之后变成了行向量 ps&#xff1a; x1^2 2x2^2 这个函数可以画成等高线,对于&#xff08;x1&#xff0c;x2&#xff09;这个点&#xff0c;可以做等高线的切线&#xff0c;再做出…

Spark Streaming(二)

声明&#xff1a; 文章中代码及相关语句为自己根据相应理解编写&#xff0c;文章中出现的相关图片为自己实践中的截图和相关技术对应的图片&#xff0c;若有相关异议&#xff0c;请联系删除。感谢。转载请注明出处&#xff0c;感谢。 By luoyepiaoxue2014 B站&#xff…

动态规划算法(2)最长回文子串详解

文章目录最长回文字串动态规划代码示例前篇&#xff1a; &#xff08;1&#xff09;初识动态规划 最长回文字串 传送门&#xff1a; https://leetcode.cn/problems/longest-palindromic-substring/description/ 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 s &qu…

大数据学习:使用Java API操作HDFS

文章目录一、创建Maven项目二、添加依赖三、创建日志属性文件四、在HDFS上创建文件五、写入HDFS文件1、将数据直接写入HDFS文件2、将本地文件写入HDFS文件六、读取HDFS文件1、读取HDFS文件直接在控制台显示2、读取HDFS文件&#xff0c;保存为本地文件一、创建Maven项目 二、添加…

Spring Security 中重要对象汇总

前言 已经写了好几篇关于 Spring Security 的文章了&#xff0c;相信很多读者还是对 Spring Security 的云里雾里的。这是因为对 Spring Security 中的对象还不了解。本文就来介绍介绍一下常用对象。 认证流程 SecurityContextHolder 用户认证通过后&#xff0c;为了避免用…

【JavaWeb】Servlet系列 --- HttpServlet【底层源码分析】

HttpServlet一、什么是协议&#xff1f;什么是HTTP协议&#xff1f;二、HTTP的请求协议&#xff08;B -- > S&#xff09;1. HTTP的请求协议包括4部分&#xff08;记住&#xff09;2. HTTP请求协议的具体报文&#xff1a;GET请求3. HTTP请求协议的具体报文&#xff1a;POST请…

生成式模型和判别式模型

决策函数Yf(x)Y f(x)Yf(x)或者条件概率分布 P(Y∣X)P(Y|X)P(Y∣X) 监督学习的任务都是从数据中学习一个模型&#xff08;也叫做分类器&#xff09;&#xff0c;应用这一模型&#xff0c;对给定的输入xxx预测相应的输出YYY,这个模型的一般形式为:决策函数Yf(x)Y f(x)Yf(x)&…

java 每日一练(6)

java 每日一练(6) 文章目录单选不定项选择题编程题单选 1.关于抽象类与最终类&#xff0c;下列说法错误的是&#xff1f;   A 抽象类能被继承&#xff0c;最终类只能被实例化。   B 抽象类和最终类都可以被声明使用   C 抽象类中可以没有抽象方法&#xff0c;最终类中可以没…

Bean 管理(工厂bean)

IOC操作Bean 管理&#xff08;FactoryBean&#xff09; 下面是在Bean 管理&#xff08;工厂bean&#xff09;之前的学习&#xff0c;基于xml方式注入集合并实现 基于xml方式注入集合并实现 &#xff1a;http://t.csdn.cn/H0ipR Spring 有两种类型bean&#xff0c;一种普通bean…

第五章. 可视化数据分析分析图表—图表的常用设置2

第五章. 可视化数据分析分析图 5.2 图表的常用设置2 本节主要介绍图表的常用设置&#xff0c;设置标题和图例&#xff0c;添加注释文本&#xff0c;调整图表与画布边缘间距以及其他设置。 7.设置标题&#xff08;title&#xff09; 1).语法&#xff1a; matplotlib.pyplot.ti…

iOS15适配 UINavigationBar和UITabBar设置无效,变成黑色

今天更新了xcode13&#xff0c;运行项目发现iOS15以上的手机导航栏和状态栏之前设置的颜色等属性都不起作用了&#xff0c;都变成了黑色&#xff0c;滚动的时候才能变成正常的颜色&#xff0c;经确认得用UINavigationBarAppearance和UITabBarAppearance这两个属性对导航栏和状态…

开发SpringBoot+Jwt+Vue的前后端分离后台管理系统VueAdmin - 前端笔记

一个spring security jwt vue的前后端分离项目&#xff01;综合运用&#xff01; 关注公众号 MarkerHub&#xff0c;回复【 VueAdmin 】可以加群讨论学习、另外还会不定时安排B站视频直播答疑&#xff01; 首发公众号&#xff1a;MarkerHub 作者&#xff1a;吕一明 视频讲解&…

半年卖8万吨辣条,卫龙再闯IPO

“辣条大王”卫龙美味全球控股有限公司&#xff08;下称“卫龙”&#xff09;于11月23日重新递表&#xff0c;继续冲刺“辣条第一股”。 作为千禧一代撑起的童年“神话”&#xff0c;卫龙的上市之路却波折重重&#xff1b;它曾于2021年5月、2021年11月及此次重启IPO。 卫龙是…

线程池ThreadPoolExecutor

线程池的生命周期 private final AtomicInteger ctl new AtomicInteger(ctlOf(RUNNING, 0)); ThreadPoolExecutor使用一个ctl变量代表两个信息&#xff0c;线程池的运行状态 (runState) 和 线程池内有效线程的数量 (workerCount)&#xff0c;高三位表示状态。 workerCount&am…

MySQL 数据库存储引擎

目录 一、存储引擎简介 二、MyISAM存储引擎 1、MylSAM介绍 2、MyISAM表支持3种不同的存储格式 3、MylSAM的特点 4、MyISAM使用的生产场景 三、InnoDB存储引擎 1、InnoDB介绍 2、InnoDB的特点 3、InnoDB适用生产场景 4、MyISAM和InnoDB的区别 四、查看和修改存储引擎…

CloudAlibaba - Nacos服务注册与配置中心

文章目录一.CloudAlibaba简介1. 介绍2. 依赖3. 主要组件4. 资料文档二.Nacos服务注册与发现1. 简介2. Nacos安装3. Nacos服务注册3.1 注册服务生产者3.2 服务消费者注册和负载4. Nacos服务中心对比三.Nacos配置中心1. 基础配置搭建2. Nacos中添加配置信息2.1 Nacos中的匹配规则…

单商户商城系统功能拆解40—分销应用—分销设置

单商户商城系统&#xff0c;也称为B2C自营电商模式单店商城系统。可以快速帮助个人、机构和企业搭建自己的私域交易线上商城。 单商户商城系统完美契合私域流量变现闭环交易使用。通常拥有丰富的营销玩法&#xff0c;例如拼团&#xff0c;秒杀&#xff0c;砍价&#xff0c;包邮…