SSM项目练习——hami音乐(三)

根据数据库环境的搭建,可以了解用户表和流派表为最简单的两张表。用户表仅用于登陆注册,流派表与其他表没有依赖关系且字段少且简单(专辑表没有依赖关系但是字段多,歌手表依赖流派表,歌曲表依赖流派、专辑和歌手三个表)。

接下来先搞后台搭建,按照流派、专辑、歌手和歌曲的顺序。

7. 后台搭建

7.1 导入页面原型

在WEB-INF下创建page文件夹,把jsp页面拷贝到page下

7.2 搭建springmvc架构

7.2.1 创建springmvc配置文件springmvc.xml
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
                <property name="features">
                    <array>
                        <value>WriteMapNullValue</value>
                        <value>WriteNullStringAsEmpty</value>
                    </array>

                </property>
                <property name="dateFormat" value="yyyy-MM-dd"></property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <context:component-scan base-package="cn.tx.controller"/>

    <!-- 视图解析器 -->
    <bean id="viewResource" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="1024000"></property>
    </bean>

    <!-- 开启主件 -->
    <mvc:default-servlet-handler/>
    <!-- 模拟创建controller -->
    <mvc:view-controller path="/index" view-name="index"/>
</beans>
7.2.2 配置web.xml

配置springmvc三大组件:servlet、监听器、拦截器。

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app
        version="2.5"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xml="http://www.w3.org/XML/1998/namespace"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <filter>
    <filter-name>filter1</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

</web-app>

启动服务器访问后台index首页

8. 流派模块开发

8.1 列表查询

8.1.1 创建查询SQL

在mybatis中定义查询的SQL,本条SQL我们考虑分页组合查询

(1)查询数据的SQL

XML 复制代码
  <!-- 分页查询:防止SQL注入风险(concat替代${}) -->
  <select id="selectByPage" parameterType="cn.tx.query.MtypeQuery" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from mtype
    <where>
      <if test="tname != null and tname != '' ">
        tname like concat('%', #{tname}, '%')
      </if>
    </where>
    limit #{startNum},#{pageSize}
  </select>

(2)查询总记录数的SQL

XML 复制代码
  <!-- 总数查询:防止SQL注入风险 + 复用条件 -->
  <select id="selectCount" parameterType="cn.tx.query.MtypeQuery" resultType="java.lang.Integer">
    select count(*) from mtype
    <where>
      <if test="tname != null and tname != '' ">
        tname like concat('%', #{tname}, '%')
      </if>
    </where>
  </select>
8.1.2 提供分页的Page对象
java 复制代码
package cn.tx.util;

import java.util.List;

/**
 * 分页工具类
 * @param <T>
 */
public class Page<T> {
    /**
     * 每页记录数(已知)
     */
    private int pageSize = 5;

    /**
     * 页码(已知)
     */
    private int pageNum = 1;

    /**
     * 指定查询条件下的总记录数(已知)
     */
    private int totalCount = 0;

    /**
     * 指定查询条件下 的总页数
     */
    private int totalPage = 1;

    /**
     * 使用sql查询的时候的开始行号
     */
    private int startNum = 0;
    
    /**
     * 结果集
     */
    private List<T> list;

    public int getPageSize() {
        return pageSize;
    }

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

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    /**
     * totalCount  pageSize   totalPage
     * 0         10       1
     * 55        10       6
     * 100       10       10
     * @return
     */
    public int getTotalPage() {
        totalPage = totalCount/pageSize;
        if(totalCount == 0 || totalCount%pageSize != 0){
            totalPage++;
        }

        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getStartNum() {
        return (pageNum -1 )*pageSize;
    }

    public void setStartNum(int startNum) {
        this.startNum = startNum;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}
8.1.3 BaseService中提供相应的分页查询接口
java 复制代码
/**
 * 分页查询
 * @param q
 * @return
 */
public Page<T> selectObjectByCondition(Q q);
8.1.4 BaseService中提供相应的分页查询接口实现
java 复制代码
@Override
public Page<T> selectObjectByCondition(Q q) {
    //获得查询对象的类对象
    Class<? extends Object> qclass = q.getClass();
    Page<T> page = new Page<T>();
    try {
        //获得getPageNo对象
        Method method = qclass.getMethod("getPageNo", null);
        //反射调用getPageNo方法
        Integer pageNo = (Integer) method.invoke(q, null);
        //创建page对象
        page.setPageNo(pageNo);
        //计算开始行号和结束行号
        int startNum = page.getStartNum();
        //好的查询对象 的设置开始行号和结束行号的方法
        Method setStartNumMethod = qclass.getMethod("setStartNum", new Class[]{int.class});
        setStartNumMethod.invoke(q, startNum);
    } catch (Exception e) {
        e.printStackTrace();
    }
    //查询结果集
    List<T> list = baseDao.selectObjectByCondition(q);
    //查询指定查询条件下的总记录数
    int count = baseDao.selectObjectByConditionCount(q);
    //把总记录数设置给page对象
    page.setTotalCount(count);
    page.setList(list);
    return page;
}
8.1.5 设置对象查询对象的分页属性
java 复制代码
package cn.tx.query;

import cn.tx.model.Mtype;

/**
 * 作为Mtype表现层接受参数的实体类
 * 与返回(响应)封装的实体类区分
 * 这是"分层设计"的最佳实践,目的是解耦、安全、可维护。
 * MtypeQuery 是"前端要什么",Mtype 是"数据库有什么"
 */
public class MtypeQuery extends Mtype {

    /**
     * 每页记录数(已知)
     */
    private Integer pageSize = 5;

    /**
     * 页码(已知)
     */
    private Integer pageNum = 1;

    /**
     * 使用sql查询的时候的开始行号
     */
    private Integer startNum = 0;

    public Integer getPageSize() {
        return pageSize;
    }

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

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Integer getStartNum() {
        return startNum;
    }

    public void setStartNum(Integer startNum) {
        this.startNum = startNum;
    }
}
8.1.6 在MtypeController里面调用Service
java 复制代码
    @Autowired
    private MtypeService mtypeService;

    /**
     * 分页条件查询所有数据
     * 1.每页数据的数量 pageSize 已知
     * 2.页码 pageNum  已知
     * 3.要查看的当前页数据集合 List<Mtype>
     * 4.开始行号 startNum  = (pageNum - 1) * pageSize
     * 5.总页数 totalPage
     * 6.数据总页数 totalCount
     * @return
     */
    @RequestMapping("/list")
    public String mytypeList(MtypeQuery Query, Model model){

        Page<Mtype> page = mtypeService.selectByPage(Query);
        model.addAttribute("page",page);
        model.addAttribute("mq",Query);
        return "mtype";
    }
8.1.7 页码数据展示

表格数据展示

html 复制代码
<table class="table table-striped table-images" style="color: white;font-size: 14px">
    <thead>
    <tr>
        <th class="hidden-xs-portrait">序号</th>

        <th class="hidden-xs">专辑</th>
        <th class="hidden-xs">流派</th>
        <th></th>
    </tr>
    </thead>
    <tbody>
        <c:forEach items="${page.list}" var="mtype" varStatus="status">
            <tr>
                <td class="hidden-xs-portrait">${status.count}</td>
                <td class="hidden-xs-portrait">${mtype.tname}</td>
                <td class="hidden-xs"> ${mtype.tdesc} </td>
                <td><button modify  class="btn btn-sm btn-primary" tid="${mtype.tid}"  type="button"> 修改 </button>
                    <button data-toggle="button" tid="${mtype.tid}" class="btn btn-sm btn-warning"> 删除 </button></td>
            </tr>
        </c:forEach>
    </tbody>
</table>

分页条数据展示 pagination.jsp

html 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="header.jsp"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<div class="clearfix text-right">
    <%--隐藏域--%>
    <input type="hidden" id="pageNum" name="pageNum" value="${mq.pageNum}">
    <input type="hidden" id="totalPage" value="${page.totalPage}">
    <ul class="pagination no-margin">
        <li id="prev" class="disabled"><a href="#">Prev</a></li>
        <c:forEach begin="1" end="${page.totalPage}" var="myPageNum">
            <li <c:if test="${myPageNum == mq.pageNum}">class="active"</c:if>><a
                    pageNumButton href="#">${myPageNum}</a></li>
        </c:forEach>
        <li id="next"><a href="#">Next</a></li>
    </ul>
</div>
</body>
</html>
8.1.8 搜索查询

搜索条件注意通过form要包含搜索条件和翻页的pageNum,通过js来提交搜索的表单,切记提交前要把pageNum置成1

javascript 复制代码
// 搜索按钮:重置页码为1
$("#search").click(function () {
    $("#pageNum").val(1);
    $("#txForm").submit();
})
8.1.9 分页条的 disabled 设置(包括翻页)
javascript 复制代码
            /**
             * 分页逻辑
             */
            var pageNum = $("#pageNum").val();
            var totalPage = $("#totalPage").val();

            pageNum = parseInt(pageNum);
            totalPage = parseInt(totalPage);

            // 禁用状态判断
            if (pageNum == 1 && pageNum == totalPage) {
                $("#prev").addClass("disabled");
                $("#next").addClass("disabled");
            }
            if (pageNum == 1 && pageNum < totalPage) {
                $("#prev").addClass("disabled");
                $("#next").removeClass("disabled");
            }
            if (pageNum > 1 && pageNum < totalPage) {
                $("#prev").removeClass("disabled");
                $("#next").removeClass("disabled");
            }
            if (pageNum > 1 && pageNum == totalPage) {
                $("#prev").removeClass("disabled");
                $("#next").addClass("disabled");
            }

            // 上一页
            $("#prev").click(function () {
                if ($(this).hasClass("disabled")) return; // 新增:阻止禁用状态点击
                $("#pageNum").val(--pageNum);
                $("#txForm").submit();
            })

            // 下一页(pageNo → pageNum)
            $("#next").click(function () {
                if ($(this).hasClass("disabled")) return; // 新增:阻止禁用状态点击
                $("#pageNum").val(++pageNum);
                $("#txForm").submit();
            })

            // 页码按钮
            $("a[pageNumButton]").click(function () {
                var pageNum = $(this).html();
                $("#pageNum").val(pageNum);
                $("#txForm").submit();
            })

8.2 流派的添加

流派添加使用layui的弹出层,预先定义好对应的div

html 复制代码
<div id="mtypePop" style="margin-right: 50px;margin-top: 50px; display: none">
    <form id="addMtypeForm" class="layui-form" method="post" action="/type/addMtype" lay-filter="example">
        <div class="layui-form-item" >
            <label class="layui-form-label">输入框</label>
            <div class="layui-input-block">
                <input  type="text" name="tname" style="color: black;"  lay-verify="title" autocomplete="off" placeholder="请输入流派名" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item layui-form-text">
            <label class="layui-form-label">文本域</label>
            <div class="layui-input-block">
                <textarea  style="color: black;" placeholder="请输入流派描述" class="layui-textarea" name="tdesc"></textarea>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn layui-btn-normal layui-btn-radius" lay-submit="" lay-filter="demo1">添加流派</button>
            </div>
        </div>
    </form>
</div>

通过js点击添加流派弹出

javascript 复制代码
var pop;
$("#addSong").click(function () {
    pop = layer.open({
        type: 1,
        area:[600, 350],
        content: $('#mtypePop')  
    });
})

提交表单

javascript 复制代码
layui.use('form', function(){
    var form = layui.form;
    //监听提交
    form.on('submit(demo1)', function(data){
        //layer.msg(JSON.stringify(data.field));
        $.ajax({
            url:"/mtype/addMtype",
            type:"post",
            data:data.field,
            dataType:"text",
            success:function (text) {
                if(text == "success"){
                    layer.msg("添加成功");
                    layer.close(pop);
                    $("#txForm").submit(); // 添加成功后刷新列表
                }
            }
        })
        //阻止页面跳转 防止同步提交 使用ajax异步提交表现
        return false;
    });
});

后台流派添加的Controller

java 复制代码
@ResponseBody
@PostMapping("/addMtype")
public String addMtype(Mtype mt){
    mtypeService.insert(mt);
    return "success";
}

8.3 流派的修改

弹出层的div

html 复制代码
<div id="mtypePop1" style="margin-right: 50px;margin-top: 50px; display: none">
    <form id="updateMtypeForm" class="layui-form" method="post" action="/type/updateMtype" lay-filter="example">
        <input type="hidden" name="tid" id="tid">
        <div class="layui-form-item" >
            <label class="layui-form-label">输入框</label>
            <div class="layui-input-block">
                <input id="ptname" type="text" name="tname" style="color: black;"  lay-verify="title" autocomplete="off" placeholder="请输入流派名" class="layui-input">
            </div>
        </div>

        <div class="layui-form-item layui-form-text">
            <label class="layui-form-label">文本域</label>
            <div class="layui-input-block">
                <textarea id="ptdesc" style="color: black;" placeholder="请输入流派描述" class="layui-textarea" name="tdesc"></textarea>
            </div>
        </div>

        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn layui-btn-normal layui-btn-radius" lay-submit="" lay-filter="demo2">修改流派</button>
            </div>
        </div>
    </form>
</div>

修改弹出层

javascript 复制代码
var pop1;
$("[modify]").click(function () {
    var tid = $(this).attr("tid");
    $.ajax({
        //原来数据回显
        url:"/mtype/getMtype",
        type:"post",
        dataType:"json",
        data:{"tid":tid},
        success:function (json) {
            $("#tid").val(json.tid);
            $("#ptname").val(json.tname);
            $("#ptdesc").val(json.tdesc);
        }
    });
    pop1 = layer.open({
        type: 1,
        area:[600, 350],
        content: $('#mtypePop1')
    });
})

流派修改的js

javascript 复制代码
layui.use('form', function(){
    var form = layui.form
    form.on("submit(demo2)",function (data) {
        $("#updateMtypeForm").ajaxSubmit({
            dataType:"text",
            success:function (text) {
                if(text == "success"){
                    layer.msg("修改成功");
                    layer.close(pop1);
                    //location.reload();
                    $("#mtFrom").submit();
                }
            }
        })
        return false;
    })
});

后台流派修改的Controller

java 复制代码
    /**
     * 流派修改回显数据方法
     * @return
     */
    @ResponseBody
    @PostMapping("/getMtype")
    public Mtype getMtype(int tid){
        Mtype mtype = mtypeService.selectByPrimaryKey(tid);
        return mtype;
    }

    /**
     * 流派修改方法
     * @param
     * @return
     */
    @ResponseBody
    @PostMapping("/updateMtype")
    public String updateMtype(Mtype mtype){
        int i = mtypeService.updateByPrimaryKey(mtype);
        return "success";
    }

8.4 流派的删除

流派删除的js

javascript 复制代码
$(".btn-warning").click(function () {
    var tid = $(this).attr("tid");
    layer.confirm('是否删除该流派?', {icon: 3, title:'提示'}, function(index){
        //layer.close(index);
        $.ajax({
            url:"/mtype/delMtype",
            dataType:"text",
            type:"post",
            data:{"tid":tid},
            success: function (text) {
                if (text == "success") {
                    layer.msg("删除成功");
                    layer.close(index);
                    //将分页条件查询的页码值归1
                    $("#pageNum").val(1);
                    $("#txForm").submit();
                }
            }
        })
    });
})

后台流派删除的Controller

javascript 复制代码
@ResponseBody
@PostMapping("/delMtype")
public String delMtype(Integer tid){
    mtypeService.deleteByPrimaryKey(tid);
    return "success";
}

9. 数据库模型的解读

一对多的关系:从流派这一端来关注

多对一的关系:从歌手端关注

箭头指向的端是1的一段,背向箭头是多的一端

相关推荐
roman_日积跬步-终至千里3 小时前
【Java并发】用 JMM 与 Happens-Before 解决多线程可见性与有序性问题
java·开发语言·spring
好奇的菜鸟4 小时前
Ubuntu 18.04 启用root账户图形界面登录指南
数据库·ubuntu·postgresql
天桥下的卖艺者4 小时前
使用R语言编写一个生成金字塔图形的函数
开发语言·数据库·r语言
爬山算法4 小时前
Hibernate(78)如何在GraphQL服务中使用Hibernate?
java·hibernate·graphql
独断万古他化4 小时前
【Spring 核心:AOP】基础到深入:思想、实现方式、切点表达式与自定义注解全梳理
java·spring·spring aop·aop·切面编程
Facechat4 小时前
鸿蒙开发入坑篇(九):本地数据库 (RDB) 深度解析
数据库·华为·harmonyos
Dxy12393102164 小时前
MySQL删除表语句详解
数据库·mysql
编程彩机4 小时前
互联网大厂Java面试:从分布式事务到微服务优化的技术场景解读
java·spring boot·redis·微服务·面试·kafka·分布式事务
bbq粉刷匠4 小时前
Java-排序2
java·数据结构·排序算法