Java课程设计:基于Javaweb的超市商品管理系统

文章目录

  • 一、项目介绍
  • 二、项目展示
  • 三、源码展示
  • 四、源码获取

一、项目介绍

  • 管理员用户:需要能够添加商品类型以及商品,能够对商品进行管理,能够查询用户信息,能够查询出售记录;
  • 普通用户:需要能够搜索商品并执行购买商品操作。能够查询购买记录,能够对余额进行充值。
  • 注册:能够进行新用户的注册。

在这里插入图片描述
功能

1.注册、登录功能。
2.管理员有商品类别管理、商品管理、用户管理、出售记录查询等功能。
3.普通用户有查看购物车、购物卡充值、修改密码、购买商品等功能。

二、项目展示

登录
在这里插入图片描述
主页
在这里插入图片描述
全部商品类
在这里插入图片描述
商品添加类
在这里插入图片描述
查询页面
在这里插入图片描述
用户列表
在这里插入图片描述

三、源码展示

连接数据库

public class JDBCUtils {private static String driver;private static String url;private static String username;private static String password;private static ResourceBundle bundle;static{bundle = ResourceBundle.getBundle("db");driver = bundle.getString("jdbc.driverClass");url = bundle.getString("jdbc.jdbcUrl");username = bundle.getString("jdbc.username");password = bundle.getString("jdbc.password");}/*** ** @return*/public static Connection getConnection() {Connection conn = null;try {Class.forName(driver);conn = DriverManager.getConnection(url, username, password);} catch (Exception e) {e.printStackTrace();}return conn;}public static void release(Connection conn) {if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}public static void release(Connection conn, PreparedStatement pstmt) {if (pstmt != null) {try {pstmt.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (pstmt != null) {try {pstmt.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}

登录类

public class Login extends JFrame {private JPanel contentPane;private JTextField txtT;private JPasswordField passwordField;private UserDao userDao = new UserDao();/*** Create the frame.*/public Login() {setResizable(false);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(100, 100, 542, 482);contentPane = new JPanel();contentPane.setBackground(SystemColor.menu);contentPane.setForeground(Color.LIGHT_GRAY);contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));setContentPane(contentPane);JLabel lblNewLabel_1 = new JLabel("密码");lblNewLabel_1.setFont(new Font("微软雅黑", Font.BOLD, 15));JButton btnNewButton = new JButton("登录");btnNewButton.setFont(new Font("微软雅黑", Font.BOLD, 15));txtT = new JTextField();txtT.setFont(new Font("微软雅黑", Font.BOLD, 15));txtT.setColumns(10);JButton btnNewButton_1 = new JButton("注册");btnNewButton_1.setFont(new Font("微软雅黑", Font.BOLD, 15));JButton btnNewButton_2 = new JButton("重置");btnNewButton_2.setFont(new Font("微软雅黑", Font.BOLD, 15));passwordField = new JPasswordField();JLabel lblNewLabel = new JLabel("用户名:");lblNewLabel.setFont(new Font("微软雅黑", Font.BOLD, 15));GroupLayout gl_contentPane = new GroupLayout(contentPane);gl_contentPane.setHorizontalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(gl_contentPane.createSequentialGroup().addGap(108).addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING, false).addGroup(gl_contentPane.createSequentialGroup().addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(gl_contentPane.createSequentialGroup().addGap(8).addComponent(lblNewLabel_1)).addGroup(gl_contentPane.createSequentialGroup().addPreferredGap(ComponentPlacement.RELATED).addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 60, GroupLayout.PREFERRED_SIZE))).addGap(18).addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addComponent(passwordField, GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE).addComponent(txtT, GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE))).addGroup(gl_contentPane.createSequentialGroup().addComponent(btnNewButton, GroupLayout.PREFERRED_SIZE, 71, GroupLayout.PREFERRED_SIZE).addGap(33).addComponent(btnNewButton_1, GroupLayout.PREFERRED_SIZE, 71, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(btnNewButton_2, GroupLayout.PREFERRED_SIZE, 71, GroupLayout.PREFERRED_SIZE))).addContainerGap(141, Short.MAX_VALUE)));gl_contentPane.setVerticalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(gl_contentPane.createSequentialGroup().addContainerGap(150, Short.MAX_VALUE).addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE).addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 38, GroupLayout.PREFERRED_SIZE).addComponent(txtT, GroupLayout.PREFERRED_SIZE, 31, GroupLayout.PREFERRED_SIZE)).addGap(33).addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE).addComponent(lblNewLabel_1, GroupLayout.PREFERRED_SIZE, 38, GroupLayout.PREFERRED_SIZE).addComponent(passwordField, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)).addGap(41).addGroup(gl_contentPane.createParallelGroup(Alignment.BASELINE).addComponent(btnNewButton).addComponent(btnNewButton_2).addComponent(btnNewButton_1)).addContainerGap(108, Short.MAX_VALUE)));contentPane.setLayout(gl_contentPane);ImageIcon bg=new ImageIcon(Login.class.getResource("/image/login.jpg"));this.setSize(bg.getIconWidth(),bg.getIconHeight());JLabel label=new JLabel(bg); label.setSize(bg.getIconWidth(),bg.getIconHeight());JPanel pan=(JPanel)this.getContentPane();pan.setOpaque(false); this.getLayeredPane().add(label,new Integer(Integer.MIN_VALUE));this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setLocationRelativeTo(null);/*** 点击方法*/btnNewButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {check();}});btnNewButton_1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {dispose();new FirstLogin().setVisible(true);}});btnNewButton_2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {txtT.setText("");passwordField.setText("");}});passwordField.addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if(e.getKeyCode()==10) {check();}}});}/*** 登录检查*/private void check() {String userName = txtT.getText();String password = passwordField.getText();Connection conn = JDBCUtils.getConnection();if(StringUtils.isEmpty(userName, password)) {JOptionPane.showMessageDialog(null, "用户名或密码不能为空");return;}User user = new User(userName,password);UserId userid = null;try {userid = userDao.login(conn,user);//返回权限if(userid!=null) {if(userid.getUserid()==1) {LoginConfig.writeUser(userName,userid.getId().toString(),password,userid.getMoney().toString());JOptionPane.showMessageDialog(null, "欢迎你管理员");dispose();AdminFrm adminfrm = new AdminFrm();adminfrm.setVisible(true);return;}else if(userid.getUserid()==0){LoginConfig.writeUser(userName,userid.getId().toString(),password,userid.getMoney().toString());JOptionPane.showMessageDialog(null, "登录成功");dispose();UserFrm userfrm = new UserFrm();userfrm.setVisible(true);return;}}else {JOptionPane.showMessageDialog(null, "登录失败");return;}} catch (Exception e) {e.printStackTrace();}}
}

登录主页

public class AdminFrm extends JFrame {private JMenu mnNewMenu;private JPanel contentPane;public JDesktopPane desk = new JDesktopPane();//为了实现一次点击只能打开一个窗口,打开变为false,关闭变为truepublic static boolean flagGoodsTypeAdd = true;public static boolean flagIntroduce = true;public static boolean flagGoodsAll = true;public static boolean flagGoodsTypeAll = true;public static boolean flagUserList = true;public static boolean flagUserShopHistory = true;public static boolean flagUpdatePassword = true;public static boolean flagChongMoney = true;/*** Create the frame.*/public AdminFrm() {setTitle("管理员界面");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setSize(893, 813);JMenuBar menuBar = new JMenuBar();setJMenuBar(menuBar);mnNewMenu = new JMenu("");menuBar.add(mnNewMenu);mnNewMenu = new JMenu();mnNewMenu.setIcon(new ImageIcon(UserFrm.class.getResource("/image/user2.jpg")));mnNewMenu.setFont(new Font("Microsoft YaHei UI", Font.BOLD | Font.ITALIC, 15));//mnNewMenu.setBackground(new Color(0, 204, 255));menuBar.add(mnNewMenu);JMenuItem paswordUpd = new JMenuItem("修改密码");paswordUpd.setIcon(new ImageIcon(UserFrm.class.getResource("/image/password.jpg")));paswordUpd.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu.add(paswordUpd);JMenuItem logout = new JMenuItem("退出登录");logout.setIcon(new ImageIcon(UserFrm.class.getResource("/image/logout.jpg")));logout.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu.add(logout);JMenu mnNewMenu_1 = new JMenu("商品维护");//mnNewMenu_1.setBackground(Color.ORANGE);mnNewMenu_1.setFont(new Font("Microsoft YaHei UI", Font.BOLD | Font.ITALIC, 15));menuBar.add(mnNewMenu_1);JMenu menu = new JMenu("商品类别管理");menu.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu_1.add(menu);JMenuItem typeAll = new JMenuItem("商品类别维护");typeAll.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));menu.add(typeAll);JMenuItem typeAdd = new JMenuItem("商品类别添加");typeAdd.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));menu.add(typeAdd);JMenu menu_1 = new JMenu("商品管理");menu_1.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu_1.add(menu_1);JMenuItem shopAll = new JMenuItem("商品维护");shopAll.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));menu_1.add(shopAll);JMenuItem shopAdd = new JMenuItem("商品添加");shopAdd.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));menu_1.add(shopAdd);JMenu mnNewMenu_3 = new JMenu("出售情况");mnNewMenu_3.setFont(new Font("Microsoft YaHei UI", Font.BOLD | Font.ITALIC, 15));menuBar.add(mnNewMenu_3);JMenuItem mntmNewMenuItem_1 = new JMenuItem("用户列表");mntmNewMenuItem_1.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu_3.add(mntmNewMenuItem_1);JMenuItem mntmNewMenuItem_2 = new JMenuItem("出售记录");mntmNewMenuItem_2.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu_3.add(mntmNewMenuItem_2);JMenu mnNewMenu_2 = new JMenu("关于我们");mnNewMenu_2.setFont(new Font("Microsoft YaHei UI", Font.BOLD | Font.ITALIC, 15));menuBar.add(mnNewMenu_2);JMenuItem mntmNewMenuItem = new JMenuItem("介绍");mntmNewMenuItem.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 15));mnNewMenu_2.add(mntmNewMenuItem);contentPane = new JPanel();contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));setContentPane(contentPane);contentPane.setLayout(new BorderLayout(0, 0));desk.setBackground(new Color(72, 209, 204));contentPane.add(desk, BorderLayout.CENTER);this.setExtendedState(JFrame.MAXIMIZED_BOTH);/*** 点击生成界面*///介绍界面mntmNewMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Introduce introduce = Introduce.getIntroduce();if (flagIntroduce) {introduce.setVisible(true);desk.add(introduce);flagIntroduce = false;}}});//商品类别管理界面typeAll.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {GoodsTypeAll goodsTypeAll = GoodsTypeAll.getGoodsTypeAll();if (flagGoodsTypeAll) {goodsTypeAll.setVisible(true);goodsTypeAll.fillJComboBox2();desk.add(goodsTypeAll);flagGoodsTypeAll = false;}}});//商品添加界面typeAdd.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {GoodsTypeAdd goodsTypeAdd = GoodsTypeAdd.getGoodsTypeAdd();if (flagGoodsTypeAdd) {goodsTypeAdd.setVisible(true);desk.add(goodsTypeAdd);flagGoodsTypeAdd = false;}}});//商品管理界面shopAll.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {GoodsAll goodsAll = GoodsAll.getGoodsAll();if (flagGoodsAll) {goodsAll.setVisible(true);goodsAll.fillJComboBox2();desk.add(goodsAll);flagGoodsAll = false;}}});//商品添加界面shopAdd.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {GoodsAdd goodsAdd = GoodsAdd.getGoodsAdd();goodsAdd.setVisible(true);goodsAdd.fillJComboBox();desk.add(goodsAdd);}});//用户列表界面mntmNewMenuItem_1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {UserList userlist = UserList.getUserList();if (flagUserList) {userlist.setVisible(true);userlist.fillTable(null);desk.add(userlist);flagUserList = false;}}});//销售记录界面mntmNewMenuItem_2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {UserShopHistory usershophistory = UserShopHistory.getShopHistory();if (flagUserShopHistory) {usershophistory.setVisible(true);usershophistory.fillTable();desk.add(usershophistory);flagUserShopHistory = false;}}});this.fillName();//修改密码界面paswordUpd.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {UpdatePassword updatePassword = UpdatePassword.getUpdatePassword();updatePassword.setVisible(true);desk.add(updatePassword);}});//充值界面mntmNewMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {ChongMoney chongMoney = ChongMoney.getChongMoney();if (flagChongMoney) {chongMoney.setMoney();chongMoney.setVisible(true);desk.add(chongMoney);flagChongMoney = false;}}});//退出登录logout.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JOptionPane.showMessageDialog(null, "退出成功");dispose();new Login().setVisible(true);}});
//		logout.addMouseListener(new MouseAdapter() {
//			@Override
//			public void mouseClicked(MouseEvent mouseEvent) {
//				JOptionPane.showMessageDialog(null, "退出成功");
//				dispose();
//				new Login().setVisible(true);
//			}
//		});}private void fillName() {ArrayList useList = LoginConfig.getUserList();String userName = useList.get(0).toString();mnNewMenu.setText(userName);}
}

四、源码获取

因为页面与源码太多了,所以页面与源码只展示了一部分,完整源码已经打包了,点击下面蓝色链接获取!

点我获取源码

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

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

相关文章

搜维尔科技:【应用】人形机器人将成为引领产业新浪潮的尖兵

特斯拉纷纷发表人形机器人计划,预示这项先进科技将成为下一个颠覆性的殖民地。人形机器人被视为继电脑、智能手机和电车之后,又一个将改变世界的创新产品。 全球人口结构正在快速老化,至2050年60岁以上人口将达22%,是现今的两倍。劳动人口短缺迫在眉睫&…

NewspaceAi之GPT使用新体验

GPT功能 使用地址:https://newspace.ai0.cn/ 上车 挂挡 踩油门,一脚到底,开始你的表演 问题1:你能做什么详细告诉我? 下面内容是GPT的回答 当然!作为一个基于GPT-4架构的AI,我能够在许多方面为…

关于FPGA对 DDR4 (MT40A256M16)的读写控制 2

关于FPGA对 DDR4 (MT40A256M16)的读写控制 2 语言 :Verilg HDL EDA工具:ISE、Vivado、Quartus II 关于FPGA对 DDR4 (MT40A256M16)的读写控制 2一、引言二、DDR4的简介四、DDR4 SDRAM状态框图 关键词&#x…

【Hachker News】如果你不需要钱,你会干什么?

Hachker News上的一个问题,标题是“如果你不需要钱,你会做什么?” 回答摘要 问题链接:What would you spend your time working on if you didn’t need money? A1: 我会把时间投入到城市周围的农村地区&#xff0c…

Matlab使用Simulink仿真实现AM和BPSK信号的解调

前言 本篇实现了基于AM和BPSK调制的通信系统,采用Bernoulli Binary Generator生成随机二元序列,码元速率为0.5秒/个。AM调制使用Sine Wave模块生成载波,频率40Hz,相位π/2。BPSK调制通过Switch模块切换相位0和π的载波。信号传输…

【java计算机专业毕设】房屋租赁系统代码源码MySQL springboot vue html maven送文档ppt

1项目功能 【java计算机专业毕设】房屋租赁系统javaweb MySQL springboot vue html maven 送报告 2项目介绍 系统功能: 房屋租赁系统包括管理员和用户和房东三种角色。 该系统包含多个功能模块,分别为管理员、用户和房东提供服务。管理员功能包括个人中…

20.2 JSON-JSON解码、映射数据类型、处理JSON响应

1. JSON解码 JSON解码,即将JSON格式在字符串转换为Go语言数据类型的变量。 函数Unmarshal接受一个JSON字节切片和一个指定目标格式的接口。而这个借口即与JSON字符串中的结果相匹配的结构体类型的变量。 定义结构体类型 type Person struct { ... }创建结构体变量…

聚鼎科技:现在的装饰画做起来难吗

在当代,装饰画作为一种体现个人品味和审美情趣的方式,已经广泛应用于各种室内空间。不少人会产生这样的疑问:在现代化技术和材料的支持下,制作一幅装饰画是变得容易了,还是依旧充满挑战? 现代科技的确为装饰画的制作带…

微信小程序查分易如何使用?

期末马上到了,老师们又开始为发放成绩而头疼了,堆积如山的试卷,密密麻麻的分数,还有那些不断响起的家长电话,真是让人心烦。别担心,今天就让我来介绍一个让老师“偷懒”神器——查分易微信小程序 第一步&am…

ROS中Twist消息类型

Twist消息类型在Robot Operating System (ROS)中是一个常见的数据结构,主要用于描述物体的线性速度和角速度。这种消息类型在ROS的geometry_msgs包中定义,常用于机器人运动控制,尤其是当需要向机器人发布速度指令时。 Twist消息由两个Vector…

6月14日 Qtday2

#include "widget.h" #include "ui_widget.h" #include <QTimer> using namespace std; Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), lab1(new QLabel(this)) //初始化一个标签显示登录状态 {//设置华清远见的标签图…

再谈 dijkstra 算法和最短路径问题

前置文章&#xff1a; dijkstra 算法为什么高效 有向图的负权值边与建模 求单源最短路径的新方法 前天晚上实现了一个基于 dijkstra 算法的求单源最短路径的新算法&#xff0c;整理了一篇文章。我非常不愿意把一些直观的问题太过于技术化&#xff0c;但多年的职业经历偏偏让一…

C#——静态成员和非静态成员详情

静态成员和非静态成员 调用: 静态属性(static) : 类名.属性名调用 非静态属性(没static) : 1.先创建对象 2.对象.属性 特点: 静态方法里面只能访问静态成员 非经态方法中可以访问所有的属性 static数据成员在类的内部声明&#xff0c;但只能在类的外部定义&#xff0c;…

【软件安装9】OpenCV多版本安装Ubuntu18.04

文章目录 一、查看已安装的Opencv版本二、安装新版本三、多版本OpenCV切换 OpenCV 官网 在此 一、查看已安装的Opencv版本 查看已安装opencv的版本 pkg-config opencv --modversion官网下载对应的版本&#xff0c;并解压 opencv3.4.3 二、安装新版本 进入前置准备里下载…

24年法考报名照片千万别乱拍,否则卡审

法考报名照片每年都有很多被卡审&#x1f62d; 常见的问题是 ①照片比例不对&#xff0c;无法上传&#xff0c;人像比例要求非常严格 ②照片像素错误&#xff0c;不能直接拿大图压缩图片&#xff0c;需要做出413*626像素的法考证件照 ③照片文件偏大&#xff0c;照片要求40-100…

单触控单输出触摸开关芯片PT2052A

1.产品概述 PT2052封装和丝印 PT2052A 是一款单通道触摸检测芯片。该芯片内建稳压电路&#xff0c;提供稳定电压给触摸感应电路使用&#xff0c;同时内部集成高效完善的触摸检测算法&#xff0c;使得芯片具有稳定的触摸检测效果。该芯片专为取代传统按键而设计&#xff0c;具有…

【精品方案】离散型制造行业智能工厂标准解决方案(49页 PPT)

引言&#xff1a;随着科技的不断进步和制造业的转型升级&#xff0c;离散型制造行业正面临着从传统制造向智能制造转型的迫切需求。离散型制造行业涉及的产品种类繁多&#xff0c;生产流程复杂&#xff0c;对生产效率、产品质量和成本控制有着极高的要求。因此&#xff0c;开发…

SQL中的UPDATE语句:别让你的数据“离家出走”

sql的update操作正式环境用的很少&#xff0c;但是在测试环境还是用的挺多的。 想象一下&#xff0c;你正在管理一个学校的数据库&#xff0c;其中有一个students表&#xff0c;记录着每个学生的信息。有一天&#xff0c;你接到通知说某个学生的年龄或成绩需要更新。这时&…

【Java并发编程之美 | 第一篇】并发编程线程基础

文章目录 1.并发编程线程基础1.1什么是线程和进程&#xff1f;1.2线程创建与运行1.2.1继承Thread类1.2.2实现Runnable接口1.2.3实现Callable接口&#xff08;与线程池搭配使用&#xff09;1.2.4小结 1.3线程常用方法1.3.1线程等待与通知1.3.2线程睡眠1.3.3让出CPU执行权1.3.4线…

漫步者开放式耳机值得买吗?漫步者、西圣、小米硬核测评pk性能!

说起开放式蓝牙耳机&#xff0c;相信大部分朋友都不会陌生。与传统的封闭式耳机相比&#xff0c;开放式蓝牙耳机不仅提升了佩戴舒适度&#xff0c;还对耳朵有良好的保护效果。特别适合喜欢户外运动和长途旅行的用户。然而&#xff0c;由于市场上产品众多&#xff0c;选择一款高…