1. 说明

本音乐播放器基于Android开发,原为我和另外两个小伙伴在上学期间一起做的一个小项目,近来有时间整理一下。之前我有文章已经介绍了播放界面的功能实现(Android音乐播放器开发),但介绍的比较粗糙,接下来会做更细致化的整理。源码已同步到Gitee仓库GitHub仓库,觉得还不错的话帮忙点个“star”吧,非常感谢。

服务端使用的是比较传统的servlet和jdbc传递数据,整理完之后,新版本会修改为SSM框架,更加简洁高效。安卓端使用的也都是基础的工具,比如音乐播放功能的实现也是借助于入门级的MediaPlayer类,目前关于安卓端没有什么更改的想法。

2. 数据库

要实现音乐播放器,数据库是必不可少的。为简化项目开发,现针对音乐播放器只设计两张表:歌曲表用户表。顾名思义,歌曲表用来存储歌曲信息,用户表用来存储用户信息。

2.1 数据库设计

涉及到的属性如下图所示:

  • 歌曲表

image-20201010205115795

  • 用户表

image-20201010205642598

(各位如果感兴趣的话,也可以将用户关闭播放器时的当前歌曲播放时长同样记录下来,这样更加符合现在主流的播放器设计)

2.2 数据库创建

数据库工具选用MySQL,为服务端提供数据支持

  1. 创建数据库
CREATE DATABASE `MusicPlayer`;
  1. 创建歌曲表
USE `MusicPlayer`;

DROP TABLE IF EXISTS `music`;
CREATE TABLE `music` (
                         `music_id` int(5) NOT NULL AUTO_INCREMENT,
                         `name` varchar(50) NOT NULL,
                         `author` varchar(50) NOT NULL,
                         `address` varchar(50) NOT NULL,
                         `img` varchar(50) NOT NULL,
                         `create_time` datetime NOT NULL,
                         `change_time` datetime,
                         `remark` text,
                         PRIMARY KEY (`music_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
  1. 创建用户表
CREATE TABLE `user` (
                        `userid` int(5) NOT NULL AUTO_INCREMENT,
                        `account` varchar(20) NOT NULL,
                        `password` varchar(20) NOT NULL,
                        `music_id` int(5) NOT NULL DEFAULT '0',
                        `pattern` int(5) NOT NULL DEFAULT '0',
                        `create_time` datetime NOT NULL,
                        `change_time` datetime,
                        `remark` text,
                        PRIMARY KEY (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

3. 数据处理

工具:IDEA

语言:Java

3.1 准备工作

MVC

业务逻辑处理涉及数据的传输与存储。这里使用了比较旧的MVC三层架构。(当然本项目相对简单,可以将所有业务揉到一起写,但为了结构更加清晰,使用了该架构)

接下来简单介绍以下设计思路。

什么是MVC?MVC由Model(模型)、View(视图)和Controller(控制器)三层组成。

web项目中,三层结构各有其作用:

  • Controller(servlet)

    • 接收用户请求(request),并作出相应请求
    • 将业务逻辑交给业务层处理
    • 控制视图的跳转
  • Model

    • 处理业务:业务逻辑(service)
    • 数据持久化:CRUD(Dao)
  • View

    • 展示数据
    • 发起servlet请求

MVC

值得注意的是,在本项目中,视图是交给Android端来处理的,而Android端有着自己的数据处理业务,因此,在服务端不存在视图层,而控制器也不负责视图跳转,只剩下数据处理的部分。

JDBC

这里简单介绍一下JDBC

程序通过数据库驱动才能和数据库进行数据的交互,SUN公司提供了Java操作数据库的规范,就是jdbc,开发人员学习jdbc接口即可,不同的数据库厂商开发各自的数据库驱动

操作数据库包含以下几个步骤:

  1. 加载驱动程序,由于不同的数据库厂商有着自己的数据库驱动,因此操作不同的数据库需要加载不同的驱动,而MySQL对应的驱动为com.mysql.jdbc.Driver

  2. 获取数据库连接,得到一个Connection

  3. 获取Statement对象,Statement对象用来执行增删查改操作。在Statement中,对数据没有进行改动的操作(也就是查询操作),执行executeQuery方法,而对数据有改动的操作(增、删、改),执行executeUpdate方法。另外,为防止SQL注入,常使用PreparedStatement对象。

  4. 如果执行的是查询操作,会返回一个结果集ResultSet

释放资源时,由后向前依次释放。

3.2 建立maven项目
  1. 新建一个maven项目

new–>project–>maven–>webapp

image-20201017165936147

  1. 导入连接jdbc依赖(pom.xml),我使用的是5.1.49的版本
  2. 导入junit依赖,方便测试
  3. 导入fastjson依赖,后续需要使用json进行数据传输
  4. servlet依赖
<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.28</version>
    </dependency>
    
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>
3.3 JavaBean

java项目中对应数据库基本表建立对应的实体类,方便数据的传输

image-20201011201053567

ORM:对象关系映射:

  • 表–>对应java类
  • 字段–>对应属性
  • 行记录–>对象
  1. 歌曲表
import java.util.Date;

public class music {
    private int musicId;
    private String name;
    private String author;
    private String address;
    private String img;
    private Date createTime;
    private Date changeTime;
    private String remark;

    public music(){
    }

    @Override
    public String toString() {
        return "music{" +
                "musicId=" + musicId +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", address='" + address + '\'' +
                ", img='" + img + '\'' +
                ", createTime=" + createTime +
                ", changeTime=" + changeTime +
                ", remark='" + remark + '\'' +
                '}';
    }

    public int getMusicId() {
        return musicId;
    }

    public void setMusicId(int musicId) {
        this.musicId = musicId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getChangeTime() {
        return changeTime;
    }

    public void setChangeTime(Date changeTime) {
        this.changeTime = changeTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}
  1. 用户表
import java.util.Date;

public class user {
    private int userId;
    private String account;
    private String password;
    private int musicId;
    private int time;
    private int pattern;
    private Date createTime;
    private Date changeTime;
    private String remark;

    public user(){

    }
    @Override
    public String toString() {
        return "user{" +
                "userId=" + userId +
                ", account='" + account + '\'' +
                ", password='" + password + '\'' +
                ", musicId=" + musicId +
                ", time=" + time +
                ", pattern=" + pattern +
                ", createTime=" + createTime +
                ", changeTime=" + changeTime +
                ", remark='" + remark + '\'' +
                '}';
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getMusicId() {
        return musicId;
    }

    public void setMusicId(int musicId) {
        this.musicId = musicId;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

    public int getPattern() {
        return pattern;
    }

    public void setPattern(int pattern) {
        this.pattern = pattern;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getChangeTime() {
        return changeTime;
    }

    public void setChangeTime(Date changeTime) {
        this.changeTime = changeTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}
3.4 Dao(持久层)

Dao层是直接操作数据库的模块,在这里真正执行增删查改命令,操作数据库借助了JDBC工具(之前已导入依赖)

image-20201011224402210

  1. db.properties

我这里使用了一个properties文件存储连接数据库的必要信息(当然这里可以直接写在业务代码中,但写在配置文件中对于后期维护来说更加简洁,更改数据库配置只需要修改配置文件即可),然后将所需数据解析到类中。

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/musicplayer?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456
  1. BaseDao

在这里将通用的逻辑代码单独拎了出来,包括建立数据库连接、关闭数据库连接、执行增删查改操作

//操作数据库的公共类
public class BaseDao {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;

    static {
        try {
            InputStream in = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");//读取配置文件返回数据流
            Properties properties = new Properties();
            properties.load(in);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            //加载驱动
            Class.forName(driver);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnextion() throws SQLException {
        //获取
        return DriverManager.getConnection(url, username, password);
    }

    //释放资源
    public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
        boolean flag = true;
        if (resultSet!=null) {
            try {
                resultSet.close();
                //GC回收
                resultSet = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }

        if (preparedStatement!=null) {
            try {
                preparedStatement.close();
                //GC回收
                preparedStatement = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }

        if (connection!=null) {
            try {
                connection.close();
                //GC回收
                connection = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }

    //编写查询公共类
    public static ResultSet execute(Connection connection, String sql,Object[] params,ResultSet resultSet,PreparedStatement preparedStatement) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            //setObject占位符从1开始,数组从0开始
            preparedStatement.setObject(i+1,params[i]);
        }
        resultSet = preparedStatement.executeQuery();
        return resultSet;
    }

    //编写增、删、改公共方法
    public static int execute(Connection connection, String sql,Object[] params,PreparedStatement preparedStatement) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            //setObject占位符从1开始,数组从0开始
            preparedStatement.setObject(i+1,params[i]);
        }
        int updateRows = preparedStatement.executeUpdate();
        return updateRows;
    }
}

编写增删查改公共方法时涉及到了java方法的重载,可以看到,查询相比增、删、改所使用的参数多一个查询结果集ResultSet

//查询
execute(Connection connection, String sql,Object[] params,ResultSet resultSet,PreparedStatement preparedStatement)
  
//增、删、改
execute(Connection connection, String sql,Object[] params,PreparedStatement preparedStatement)

CRUD

CRUD就是对数据库执行增删查改操作,程序写到这里就需要考虑到音乐播放器的需求了。

image-20201011155503120

为简化项目开发,现只提出五点数据需求(什么?竟然没有歌曲的添加、歌曲信息的修改……因为如果写这些的话我还得再加一个后台管理系统,目前没这个想法(手动狗头))

前三点都非常好理解,现在介绍一下第四点和第五点。

  • 退出时保存当前正在播放的内容:当用户再次打开APP时显示的是上次关闭APP时所听的歌曲
  • 获取歌曲所有信息,这个目的是用于音乐播放的数据来源。针对歌曲数量比较少的情况使用此方法还可,但是一旦歌曲数量足够多,加载所有歌曲信息将会占据大量内存空间,因此这里需要各位大佬自行优化
  1. 两个接口

分别给music表和user表建立对应的接口,表示对这两个表进行增删查改操作

  • MusicDao
public interface MusicDAO {
    //获取所有歌曲信息
    public List<Music> getMusicList(Connection connection) throws SQLException;
}
  • UserDao
public interface UserDao {

    //获取用户信息
    public User getUser(Connection connection, String account) throws SQLException;

    //添加用户信息
    public int insertUser(Connection connection, User user) throws SQLException;

    //更改密码
    public int changePassword(Connection connection, User user) throws SQLException;

    //退出时保存当前所听歌曲
    public int saveMusic(String account, int musicId) throws SQLException;
}
  1. UserDao实现类(UserDaoImpl)
  • getUser(获取用户信息)
public User getUser(Connection connection, String account) throws SQLException {
    ResultSet resultSet = null;
    PreparedStatement preparedStatement = null;
    User user = new User();

    if (connection!=null) {
        String sql = "select * from user where account = ?";
        Object[] params = {account};  //存储参数
        resultSet = BaseDao.execute(connection, sql, params, resultSet, preparedStatement);
        if(resultSet.next()){
            user.setAccount(account);
            user.setMusicId(resultSet.getInt("music_id"));
            user.setPassword(resultSet.getString("password"));
            user.setPattern(resultSet.getInt("pattern"));
            user.setCreateTime(resultSet.getDate("create_time"));
            user.setChangeTime(resultSet.getDate("change_time"));
            user.setRemark(resultSet.getString("remark"));
        }
        BaseDao.closeResource(null,preparedStatement,resultSet);
    }

    return user;
}
  • insertUser(添加用户信息)
public int insertUser(Connection connection, User user) throws SQLException {
    PreparedStatement preparedStatement = null;
    int insertRows = 0;
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

    if (connection!=null) {
        String sql = "insert into user(`account`, `password`, `create_time`) values(?,?,?)";
        Object[] params = {user.getAccount(), user.getPassword(), df.format(new Date())};
        insertRows = BaseDao.execute(connection, sql, params, preparedStatement);
        BaseDao.closeResource(null,preparedStatement,null);
    }

    return insertRows;
}

到这里,已经实现了添加用户信息查询用户信息两项功能,那么我们可以进行一轮测试,先插入一个用户,再查询该用户信息。借助于junit,可以很方便地对代码进行测试。

//测试添加用户信息

@Test
public void testInsert() throws SQLException {
    Connection connection = null;
    int i = 0;

    try {
        connection = BaseDao.getConnextion();
    } catch (SQLException e) {
        e.printStackTrace();
    }

    User user = new User();
    user.setAccount("cun");
    user.setPassword("123456");

    if(connection!=null){
        i = insertUser(connection, user);
    }
    if(i!=0){
        System.out.println("插入成功");
    }
    BaseDao.closeResource(connection,null,null);   //在哪里开启的connection,就在哪里关闭
}

测试结果如下,根据测试结果可以看出,我们已经插入了一条数据

image-20201011174930752

//测试用户信息查询

@Test
public void testSelect() throws SQLException {
    Connection connection = null;
    String account = "cun";
    User user = null;

    try {
        connection = BaseDao.getConnextion();
    } catch (SQLException e) {
        e.printStackTrace();
    }

    user = getUser(connection, account);
    if(user != null){
        System.out.println(user.getPassword());
    }
    BaseDao.closeResource(connection,null,null);
}

测试结果如下,根据测试结果可知,查询出的用户密码正是我们所插入的用户密码。由此表明,两个功能实现正常。

image-20201011175905472

  • changePassword(更改用户密码)
public int changePassword(Connection connection, User user) throws SQLException {

    PreparedStatement preparedStatement = null;
    int updateRows = 0;
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

    if(connection!=null){
        String sql = "update user set password=?, change_time=? where account = ?";
        Object[] params = {user.getPassword(), df.format(new Date()), user.getAccount()};
        updateRows = BaseDao.execute(connection, sql, params, preparedStatement);
        BaseDao.closeResource(null,preparedStatement,null);
    }

    return updateRows;
}

测试密码更改

@Test
public void testUpdate() throws SQLException {
    Connection connection = BaseDao.getConnextion();

    User user1 = new User();
    user1.setAccount("cun");
    user1.setPassword("456789");

    int i = changePassword(connection, user1);

    User user2 = new User();
    if(i>0){
        user2 = getUser(connection, "cun");
    }
    System.out.println(user2.getPassword());

    BaseDao.closeResource(connection,null,null);
}

密码已经由原来的123456修改为456789了,修改成功!

image-20201011200833200

  • saveMusic(保存音乐id)
public int saveMusic(Connection connection, String account, int musicId) throws SQLException {

    PreparedStatement preparedStatement = null;
    int updateRows = 0;

    if(connection!=null){
        String sql = "update user set music_id=? where account = ?";
        Object[] params = {musicId, account};
        updateRows = BaseDao.execute(connection, sql, params, preparedStatement);
        BaseDao.closeResource(null,preparedStatement,null);
    }

    return updateRows;
}

测试

@Test
public void test() throws SQLException {
    Connection connection = BaseDao.getConnextion();

    int i = saveMusic(connection, "cun", 5);

    User user = new User();
    if(i>0){
        user = getUser(connection, "cun");
    }
    System.out.println(user.getMusicId());

    BaseDao.closeResource(connection,null,null);
}

测试结果表明已将音乐id保存到了用户信息中了,测试成功!

image-20201011202431479

  1. MusicDao实现类(MusicDaoImpl)

五点需求现在只剩下获取所有歌曲信息

  • getMusicList
public List<Music> getMusicList(Connection connection) throws SQLException {

    ArrayList<Music> musicList = new ArrayList<Music>();
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;

    if (connection!=null) {
        String sql = "select * from music";
        Object[] params = {};
        resultSet = BaseDao.execute(connection, sql, params, resultSet, preparedStatement);
        while(resultSet.next()){
            Music music = new Music();
            music.setName(resultSet.getString("name"));
            music.setAuthor(resultSet.getString("author"));
            music.setAddress(resultSet.getString("address"));
            music.setImg(resultSet.getString("img"));
            music.setCreateTime(resultSet.getDate("create_time"));
            music.setChangeTime(resultSet.getDate("change_time"));
            music.setRemark(resultSet.getString("remark"));

            musicList.add(music);
        }
        BaseDao.closeResource(null,preparedStatement,resultSet);
    }
    return musicList;
}

要想进行测试,数据库中music表中必须存在数据,现在直接插入一条歌曲信息

INSERT INTO `music` VALUES ('0', '下坠', 'Corki', 'xiazhui.mp3', 'xiazhui.jpg', now(), null, null);

测试getMusicList方法

@Test
public void test() throws SQLException {
    Connection connection = BaseDao.getConnextion();

    List<Music> musicList = getMusicList(connection);
    if(musicList.size()>0){
        System.out.println(musicList);
    }
    BaseDao.closeResource(connection,null,null);
}

image-20201011210033188

3.5 Service(服务)

Service层处理内部逻辑。Servlet接收到请求后,将具体的业务逻辑交给Service去处理,涉及到数据的部分,Service再去调用Dao层实现数据的增删查改。

实际上,在本项目中,Service层的大部分程序在Dao层的测试程序中出现过,因此这一部分非常容易理解。

  1. 还是建立两个接口。

image-20201012185342710

  • MusicService
public interface MusicService {
    
    //获取所有的歌曲信息
    public List<Music> getMusicList();
}
  • UserService
public interface UserService {

    //用户登录
    public User login(String account);

    //根据用户账户修改密码
    public boolean updatePwd(String account, String password);

    //注册新用户
    public boolean insertUser(String account, String password);

    //保存当前歌曲信息
    public boolean updateMusic(String account, int musicId);
}
  1. UserService实现类(UserServiceImpl)
  • dao层

业务层都会调用dao层,所以我们直接使用无参构造引入dao层

private UserDao userDao;

public UserServiceImpl(){
    userDao = new UserDaoImpl();
}
  • login(用户登录)
public User login(String account, String password) {
    Connection connection = null;
    User user = null;

    try {
        connection = BaseDao.getConnextion();
        user = userDao.getUser(connection, account);
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        BaseDao.closeResource(connection, null, null);
    }

    return user;
}
  • updatePwd(更改密码)
public boolean updatePwd(String account, String password) {
    boolean flag = false;
    Connection connection = null;

    User user = new User();
    user.setAccount(account);
    user.setPassword(password);

    try {
        connection = BaseDao.getConnextion();
        if(userDao.changePassword(connection, user)>0){
            flag = true;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        BaseDao.closeResource(connection, null, null);
    }

    return flag;
}
  • insertUser(插入新用户)
public boolean insertUser(String account, String password) {
    boolean flag = false;
    Connection connection = null;

    User user = new User();
    user.setAccount(account);
    user.setPassword(password);

    try{
        connection = BaseDao.getConnextion();
        if(userDao.insertUser(connection, user)>0){
            flag = true;
        }
    }catch (SQLException e) {
        e.printStackTrace();
    }finally {
        BaseDao.closeResource(connection, null, null);
    }

    return flag;
}
  • updateMusic(保存用户的歌曲信息)
public boolean updateMusic(String account, int musicId) {
    boolean flag = false;
    Connection connection = null;

    try{
        connection = BaseDao.getConnextion();
        if(userDao.saveMusic(connection, account, musicId)>0){
            flag = true;
        }
    }catch (SQLException e) {
        e.printStackTrace();
    }finally {
        BaseDao.closeResource(connection, null, null);
    }

    return flag;
}
  1. MusicService实现类(MusicServiceImpl)
  • 同样首先拿到MusicDao
private MusicDao musicDao;

public MusicServiceImpl(){
    musicDao = new MusicDaoImpl();
}
  • getMusicList(获取全部歌曲信息)
public List<Music> getMusicList() {
    List<Music> musicList = new ArrayList<Music>();
    Connection connection = null;

    try {
        connection = BaseDao.getConnextion();
        musicList = musicDao.getMusicList(connection);
    }catch (SQLException e) {
        e.printStackTrace();
    }finally {
        BaseDao.closeResource(connection, null, null);
    }

    return musicList;
}
3.6 Util(工具类)

在写servlet层之前,先构建一个工具类。

由于从数据库获取的数据都使用了实体类,而服务端的数据需要向Android端进行传输,使用实体类不方便,这里将数据进一步转化为json文件进行传输。

jsonUtil

  • getUserJson

提供了User类转json的方法。

//user转json
public String getUserJson(User user){
    JSONObject userJson = new JSONObject();

    if(user!=null){
        userJson.put("userId", user.getUserId());
        userJson.put("account", user.getAccount());
        userJson.put("password", user.getPassword());
        userJson.put("music_id", user.getMusicId());
        userJson.put("pattern", user.getPattern());
        userJson.put("createTime", user.getCreateTime());
        userJson.put("changeTime", user.getChangeTime());
        userJson.put("remark", user.getRemark());
    }

    return userJson.toString();
}
  • getMusicJson
//music转json
public String getMusicJson(Music music){
    JSONObject musicJson = new JSONObject();

    if(music != null){
        musicJson.put("musicId", music.getMusicId());
        musicJson.put("name", music.getName());
        musicJson.put("author", music.getAuthor());
        musicJson.put("address", music.getAddress());
        musicJson.put("img", music.getImg());
        musicJson.put("createTime", music.getCreateTime());
        musicJson.put("changeTime", music.getChangeTime());
        musicJson.put("remark", music.getRemark());
    }

    return musicJson.toString();
}
  • getJsonArray
//List<Music>转JsonArray
public String getJsonArray(List<Music> musicList){

    JSONObject musicJson = new JSONObject();
    JSONArray musicJsonArray = new JSONArray();

    for (Music music:musicList) {
        musicJson.put("musicId", music.getMusicId());
        musicJson.put("name", music.getName());
        musicJson.put("author", music.getAuthor());
        musicJson.put("address", music.getAddress());
        musicJson.put("img", music.getImg());
        musicJson.put("createTime", music.getCreateTime());
        musicJson.put("changeTime", music.getChangeTime());
        musicJson.put("remark", music.getRemark());

        musicJsonArray.add(musicJson);
    }

    return musicJsonArray.toString();
}
3.7 Servlet
  1. LoginServlet

用于登录系统。这里继承了HttpServlet,需要改写父类的doGetdoPost方法

public class LoginServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html;charset=utf-8");
        String responseJson = "";

        //从android端获取用户名和密码
        String userAccount = req.getParameter("account");
        String userPassword = req.getParameter("password");

        //与数据库中的密码进行比对
        UserService userService = new UserServiceImpl();
        User user = userService.login(userAccount);

        if(user != null){
            JsonUtil jsonUtil = new JsonUtil();
            responseJson = jsonUtil.getUserJson(user);
        }        

        resp.getWriter().append(responseJson).flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. UpdatePwdServlet

更改密码,注意这里首先验证旧密码是否符合数据库中保存的密码,符合才能进行更新操作

public class UpdatePwdServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String response = "";

        //从android端获取用户名和密码
        String userAccount = req.getParameter("account");
        String userPassword = req.getParameter("oldPassword");
        String newPassword = req.getParameter("newPassword");

        //先验证旧密码与数据库中的是否相同
        UserService userService = new UserServiceImpl();
        User user = userService.login(userAccount);
        if(user != null){
            if(user.getPassword().equals(userPassword)){
                boolean flag = userService.updatePwd(userAccount, newPassword);
                if(flag){
                    response = "{'result':'修改成功!'}";
                }
                else{
                    response = "{'result':'修改失败!'}";
                }
            }
            else{
                response = "{'result':'旧密码错误!'}";
            }
        }

        resp.getWriter().append(response).flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. SignUpServlet

注册新用户

public class SignUpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String response = "";

        //从android端获取用户名和密码
        String userAccount = req.getParameter("account");
        String userPassword = req.getParameter("password");

        UserService userService = new UserServiceImpl();
        boolean flag = userService.insertUser(userAccount, userPassword);
        if(flag){
            response = "{'result':'注册成功!'}";
        }else{
            response = "{'result':'注册失败!'}";
        }
        resp.getWriter().append(response).flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. SaveMusicServlet

向用户表中保存歌曲信息

public class SaveMusicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String response = "";

        //从android端获取用户名和密码
        String userAccount = req.getParameter("account");
        int musicId = Integer.parseInt(req.getParameter("musicId"));

        UserService userService = new UserServiceImpl();
        boolean flag = userService.updateMusic(userAccount, musicId);
        if(flag){
            response = "{'result':'保存成功!'}";
        }else{
            response = "{'result':'保存失败!'}";
        }
        resp.getWriter().append(response).flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. GetMusicListServlet

获取所有歌曲信息

public class GetMusicListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String response = "";

        MusicService musicService = new MusicServiceImpl();
        List<Music> musicList =  musicService.getMusicList();
        if(musicList.size()>0){
            JsonUtil jsonUtil = new JsonUtil();
            response = jsonUtil.getJsonArray(musicList);
        }
        else{
            response = "{'result':'获取歌曲列表失败!'}";
        }

        resp.getWriter().append(response).flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

4. 配置Tomcat

在IDEA中直接配置一个Tomcat

  1. Run–>Edit Configurations

image-20201017183335823

  1. “+”–>Tomcat Server–>Local

image-20201017183443176

  1. 修改Name

image-20201017183546163

  1. Deloyment–>"+"–>Artifact

image-20201017183647996

  1. 选中当前项目,一定要选择下面这种类型的

image-20201017183829741

  1. 修改Application context–>Apply–>ok

image-20201017184000413

配置完成后就会显示刚配置的tomcat,直接点击“运行”即可启动tomcat

image-20201017184850911

  1. 配置servlet映射,这个是为了在其它环境访问服务端(web.xml
  • servlet:绑定servlet类
  • servlet-mapping:设置访问地址url
<?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">

  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>servlet.user.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>SaveMusicServlet</servlet-name>
    <servlet-class>servlet.user.SaveMusicServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>SaveMusicServlet</servlet-name>
    <url-pattern>/SaveMusic</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>SignUpServlet</servlet-name>
    <servlet-class>servlet.user.SignUpServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>SignUpServlet</servlet-name>
    <url-pattern>/SignUp</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>UpdatePwdServlet</servlet-name>
    <servlet-class>servlet.user.UpdatePwdServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UpdatePwdServlet</servlet-name>
    <url-pattern>/UpdatePwd</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>GetMusicListServlet</servlet-name>
    <servlet-class>servlet.music.GetMusicListServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>GetMusicListServlet</servlet-name>
    <url-pattern>/GetMusicList</url-pattern>
  </servlet-mapping>
  
</web-app>
  1. 测试

使用GET方法请求服务端数据(GET和POST是HTTP请求的两种基本方法,具体区别这里不再赘述),具体表现在使用GET方法时数据被放在请求的URL中。

  • 启动Tomcat

启动成功后,会在浏览器打开默认的web界面,此时的url是http://localhost:8080/musicplayer/

  • 测试登录

url:http://localhost:8080/musicplayer/login?account=cun&password=456789

配置servlet映射后,访问登录的servlet即为/login,在?后加入参数,以上的url表示设置accountcun,设置password456789。浏览器的显示结果如下,由结果可知,数据传输成功。

image-20201017185726916

使用错误的密码进行测试:

image-20201017190635429

  • 测试修改密码

url:http://localhost:8080/musicplayer/UpdatePwd?account=cun&oldPassword=456789&newPassword=123456

image-20201018001837394

再看一遍数据库,发现数据确实已经被修改为123456

image-20201018001956045

  • 测试注册

url:http://localhost:8080/musicplayer/SignUp?account=abc&password=456789

image-20201018163500480

数据库中已经有了账户为abc的数据

image-20201018163651874

  • 测试保存歌曲信息到用户表中

url:http://localhost:8080/musicplayer/SaveMusic?account=abc&musicId=4

image-20201018164004221

数据库中的信息已经被更改

image-20201018164112823

  • 测试获取歌曲信息

url:http://localhost:8080/musicplayer/GetMusicList

image-20201018164608919

5. 结语

至此,服务端代码已基本完成,一部分程序还没有做测试,下一步编写Android程序,结合Tomcat,测试在服务端提取数据。

回顾一下,服务端:

  • 工具:IDEA开发工具、MySQL数据库、Tomcat;
  • 技术:servlet、jdbc、MVC架构

6.

近来发现一些小伙伴不看开头啊。

程序已经放到两个仓库了,觉得有帮助到你的话,就请给本文点个赞,给仓库点个star吧!万分感谢!

Gitee仓库

GitHub仓库

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐