springboot项目新感悟

1. 前言

这几天老师带领我们做一个标准的Java web项目,提供了前端的源码,是一次很好的练习机会,老师带领做的是基于自己引入包的SSM框架,而自己是用springboot管理开发的。做的过程中也学到了很多新的知识,总结一下,希望以后温故而知新。

2. 前端

2.1 头文件

引入thymeleaf模板需要添加

<html lang="en" xmlns:th="http://www.thymeleaf.org">

因为是老师给的前端静态界面,IDEA中仍然无法提示出th:xxx。后发现原因是最上面的标签影响了

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--上面这个即使加了thymeleaf也会无法提示,所以改成下面这个-->
<!DOCTYPE html>

还有一个就是相对/绝对路径的问题
开头为/的路径为绝对路径,引入css/js/…最好使用绝对路径,这样在跳转之后不会找不到上述文件

	<link href="/css/main.css" rel="stylesheet" type="text/css" media="all" />
    <script src="/js/jquery-1.4.2.min.js" type="text/javascript"></script>

文件的路径存放位置为:在这里插入图片描述

2.2 js/ajax

自己只是懂一丢丢前端的知识,但开发中用到了几个js/ajax记录一下

2.2.1 submit()

由于提交按钮不在form表单中,所以需要一个简单的js来进行提交

	<script type="text/javascript">
        function submit(){
            document.getElementById("institutionCreat").submit();
        }
    </script>

2.2.2 ajax

需求是这样的:进入界面会显示所有的机构列表,选中某一机构后,会显示旗下的所有科室列表(如同选中省后显示所有的市)

<script type="text/javascript">
    var orgId = null;
    $("select[id=selectO]").change(function(){
        orgName = $(this).val();
        $.ajax({
            type:"POST",
            async:true,  //异步
            dataType:"json",
            url: "/part01/content/member-section.html",    //url地址
            data:{"orgName":orgName},
            success : function (data) {   //请求成功时的返回函数
                // var list =  JSON.stringify(data);
                for (var i = 0; i < data.length; i++) {
                    var option = document.createElement("option");
                    $(option).val(data[i]);
                    $(option).text(data[i]);
                    $('#dss').append(option);
                }
            }
        });
    });

</script>

其中第一个select[id=selectO]的意思为找到对应的select,selectO是其id
第二个dss是第二个下拉列表的id
需要注意的是,这个ajax需要放在页面最下方,原因是:页面进行加载,从上到下,如果先加载到ajax,则找不到对应的select(这个还未加载)所以失效。

/**
     * 根据机构名称得到旗下的科室列表
     * @param orgName
     * @param model
     * @return
     */
    @RequestMapping("/part01/content/member-section.html")
    @ResponseBody
    public List<String> StuffRelationSectionView(@RequestParam(required=true,name = "orgName") String orgName,
                                           		 Model model) {
        Integer orgId = organizationService.getIdByOrgName(orgName);
        List<String> divNameList = sectionService.getSectionDivNameByOrgId(orgId);
        List<String> allOrgName = organizationService.getAllOrgName();
        model.addAttribute("allOrgName",allOrgName);
        model.addAttribute("divNameList",divNameList);
        return divNameList;
//        return "/part01/content/member-relation.html";
    }

用@ResponseBody标记为返回json,直接返回json数据

2.2 date格式

一般来说,采用th:text标记的date日期都是外国格式,对我们来说很奇怪
在这里插入图片描述

<td align="center" th:text="${orgInformation.standAloneDate}"></td>
<td align="center" th:text="${#calendars.format(orgInformation.standAloneDate,'yyyy-MM-dd HH:mm:ss')}"></td>

很明显的差距,修改方法也很简单,其实不止#calendars,还有其他的一些封装好的类,具体我也没用过。

2.3 th:if

需要注意的是,如果数据是字符串类型的,判断是否相等需要带引号。尤其注意有时需要用varchar(1)来保存一个魔法值,比如1->博士等等,此时看似是数字,其实是字符串,判断就可能有误。正确事例如下:

<td th:if="${leader.title=='1'}">初级(医(技)师)</td>

2.4 input多选

2.4.1 radio

对于多选项radio,只需将每个radio的name改成需要传的值即可

<td align="left" colspan="4" >
    <input type="radio" name="exeType" id="radio5" value="2" />行政部门
    <input type="radio" name="exeType" id="radio6" value="1" />卫生监督机构
    <input type="radio" name="exeType" id="radio7" value="3" />协作单位
</td>

2.4.1 select

select 将select的name属性改为需要传的值即可

<select name="orgLevel" id="select">
   <!--<option value="">请选择</option>-->
    <option value="1">未定级</option>
    <option value="2">副科级以下</option>
    <option value="3">副科级</option>
    <option value="4">科级</option>
    <option value="5">副处级</option>
    <option value="6">处级</option>
    <option value="7">副厅局级</option>
    <option value="8">厅局级</option>
</select>

2.5 数据回显

数据回显的意思是,当我们对一个表进行修改时,页面要提前先展示原值,方便修改。
后端逻辑就是传回id,查询出整个表数据,填充到前端界面

2.5.1 大多数

简单的一部分就是直接使用th:value填充

2.5.2 radio

<td align="left" colspan="4" >
   <input type="radio" name="exeType" id="radio5" value="2"  th:field="*{organization.exeType}"/>行政部门
   <input type="radio" name="exeType" id="radio6" value="1"  th:field="*{organization.exeType}"/>卫生监督机构
   <input type="radio" name="exeType" id="radio7" value="3"  th:field="*{organization.exeType}"/>协作单位
</td>

使用th:field

2.5.3 option

<select name="edu" id="select">
    <option value="1" th:selected="${stuff.edu=='1'}">博士</option>
    <option value="2" th:selected="${stuff.edu=='2'}">硕士</option>
    <option value="3" th:selected="${stuff.edu=='3'}">本科</option>
    <option value="4" th:selected="${stuff.edu=='4'}">大专</option>
    <option value="5" th:selected="${stuff.edu=='5'}">中专</option>
    <option value="6" th:selected="${stuff.edu=='6'}">高中</option>
    <option value="7" th:selected="${stuff.edu=='7'}">初中</option>
    <option value="8" th:selected="${stuff.edu=='8'}">无学历</option>
    <option value="9" th:selected="${stuff.edu=='9'}">不详</option>
</select>

2.6 隐藏的input

需求如下:我们要对一个表进行修改,需要传递id,此时需要隐藏一个input,存储隐藏的信息

<input type="hidden" th:value="${organization.id}" name="id">

3. 后端

3.1 mapper层

我用的是注解版mybatis,sql直接写在了注解上。

3.1.1 脚本

mybatis有很多有用的脚本,在xml版中,通常用<>来写,在注解版中,写法如下
代码一

	@Select("<script> " +
            "SELECT  orgName,equ3Count " +
            "FROM t_d0_orgattached " +
            "where 1=1 " +
            "<if test='orgName!=null'> and orgName = #{orgName}</if>" +
            "</script>")
    List<Orgattached> getEquipment(Orgattached orgattached);

代码二

	@Select("<script>" +
            "SELECT orgName," +
            "COUNT(CASE WHEN gender='1' THEN 1 END) manNumber, " +
            "COUNT(CASE WHEN gender='2' THEN 1 END) womenNumber, " +
            "COUNT(CASE WHEN edu='1' THEN 1 END) doctorNumber ," +
            "COUNT(CASE WHEN edu='2' THEN 1 END) masterNumber ," +
            "COUNT(CASE WHEN edu='6' THEN 1 WHEN edu='7' THEN 1 WHEN edu='8' THEN 1 WHEN edu='9' THEN 1 END) lowerMiddleNumber ," +
            "COUNT(CASE WHEN ROUND(DATEDIFF(CURDATE(),birthdate)/365.2422)&gt;=0 AND ROUND(DATEDIFF(CURDATE(),birthdate)/365.2422)&lt;=25 THEN 1 END) numberLower25," +
            "COUNT(CASE WHEN ROUND(DATEDIFF(CURDATE(),birthdate)/365.2422)&gt;=26 AND ROUND(DATEDIFF(CURDATE(),birthdate)/365.2422)&lt;=30 THEN 1 END) number26To30," +
            "COUNT(CASE WHEN jobLevel='1' THEN 1 END) jobLevel1 ," +
            "COUNT(CASE WHEN jobLevel='2' THEN 1 END) jobLevel2 ," +
            "COUNT(CASE WHEN title='14' THEN 1 END) title1 ," +
            "COUNT(CASE WHEN title='1' THEN 1 WHEN title='2' THEN 1 WHEN title='3' THEN 1 WHEN title='4' THEN 1 WHEN title='5' THEN 1 END) title4 ," +
            "COUNT(CASE WHEN title='15' THEN 1 END) title5 " +
            "FROM ( " +
            "SELECT s.*,o.orgName " +
            "FROM t_d0_stuff s LEFT JOIN t_d0_organization o " +
            "ON s.orgId=o.id " +
            ") stuffPlus " +
            "where 1=1 " +
            "<if test='orgName!=null'> and orgName = #{orgName}</if>" +
            "GROUP BY orgId" +
            "</script>")
    List<StuffComposition> getStuffComposition(StuffComposition stuffComposition);

代码一是简单的一个例子,代码二是一个复杂的例子(意思不是例子二是例子一的加强版)
在字符串中添加<script>来注明使用脚本。
同时,上述代码还解决了多条件查询的问题。

3.1.1.1 注意1

如果只传入个值,如上述代码,必须由对象来传入,这点很奇怪,首先是一个值,如果是两个值就没有影响。原因暂时不知道,用对象传会正常执行。

3.1.1.2 注意2

对于代码一,我这里为了保证后续条件都可以格式正确,所以先写了一个 ,1==1,然后用if标签加and xxx,这样格式可以正确,同时官网也提供了一种<where>标签可以自动识别之类的,
详情参考:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

3.1.1.3 注意3

由于对应xml语言,所以需要对<>进行处理

&gt; 对应 >
&lt; 对应 <
3.1.1.4 注意4

代码二提供了对表进行统计的sql语句,包括:统计男女个数,统计年龄(这里数据库只给了生日,需要函数运算)

3.1.2 返回自增ID

需求:增加一个机构,同时需要增加一个机构详情,机构详情里有机构的自增id,所以需要insert机构的时候返回自增的ID

	@Insert("insert into " +
            "t_d0_organization " +
            "(orgNo, orgCode, orgName, exeType, areaCode, linkAdd, listingDate) " +
            "values" +
            "(#{orgNo},#{orgCode},#{orgName},#{exeType},#{areaCode},#{linkAdd},#{listingDate})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    Integer insertOneOrganization(Organization organization);

解决方案如上,添加@Options(useGeneratedKeys = true, keyProperty = “id”),其中此处的id即为数据库中机构的ID列名。
注意,返回的值并不在return中,而是自动绑定到了传入的对象中

3.2 service层

我的service层并没有太多的逻辑,都是直接返回mapper层的值,只有一个有逻辑。就是上面对应那个统计的函数
需求:统计一些数据后,比如,级别1 x人,级别2 y人…还需要统计共多少人。
此时可以在service层直接计算上述统计出来数据的和。

3.3 controller层

controller层没有使用什么特别的用法
使用 Model model
model.addAttribute(“allOrgName”,allOrgName);
可以将信息放入request域中

3.4 VO

显然,我们有时需要对数据打包,而PO对象可能不适合,此时我们可以添加一个VO对象来存数据。
例如上面提到的对数据进行统计,需要一个新的VO来存数据

3.5 配置文件

#关闭缓存便于调试
spring.thymeleaf.cache=false
#添加日志详情
spring.http.log-request-details=true
#对mapper层进行更高级别的日志,如果是debug则会展示进行了什么sql,查询了什么结果...
logging.level.cn.edu.hrbeu.group15.mapper=debug

4 分页

我这里采用的分页是pagehelper,是一个包,另外的解决方案是对sql进行修改手动limit

4.1 pom.xml中添加依赖

		<!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

4.2 配置文件

# Pagehelper #分页插件
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql

4.3 后端controller

	@RequestMapping("/part01/content/institution-list.html")
    public String InstitutionList(@RequestParam(required=true,defaultValue="1") Integer page, 
    							  Model model) {
        //开启分页,10就是条数
        PageHelper.startPage(page,10);
		//正常查询
        List<Organization> all = organizationService.getAll();
        //对结果进行包装
        PageInfo<Organization> organizationPageInfo = new PageInfo<>(all);
        //将正常结果与包装结果均放入request域中
        model.addAttribute("organizationPageInfo",organizationPageInfo);
        model.addAttribute("all",all);
        return "part01/content/institution-list.html";
    }

4.4 前端 html

显示数据是正常显示

<td align="center" th:text="${organization.orgCode}">0123456-01</td>

页面展示

<li><a th:href="@{'/part01/content/institution-list.html?page='+${organizationPageInfo.firstPage}}">首页</a></li>
<li><a th:href="@{'/part01/content/institution-list.html?page='+${organizationPageInfo.prePage}}">上页</a></li>
<li><a href="/part01/content/institution-list.html?page=1">1</a></li>
<li><a href="/part01/content/institution-list.html?page=2">2</a></li>
<li><a th:href="@{'/part01/content/institution-list.html?page='+${organizationPageInfo.nextPage}}">下页</a></li>
<li><a th:href="@{'/part01/content/institution-list.html?page='+${organizationPageInfo.lastPage}}">尾页</a></li>

其实与正常数据显示其实大同小异
那些数据属性都在PageInfo这个类中,点进去就可以看到

public class PageInfo<T> extends PageSerializable<T> {
    private int pageNum;
    private int pageSize;
    private int size;
    private int startRow;
    private int endRow;
    private int pages;
    private int prePage;
    private int nextPage;
    private boolean isFirstPage;
    private boolean isLastPage;
    private boolean hasPreviousPage;
    private boolean hasNextPage;
    private int navigatePages;
    private int[] navigatepageNums;
    private int navigateFirstPage;
    private int navigateLastPage;

就是上述属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当前课程中博客项目的实战源码是我在 GitHub上开源项目 My-Blog,目前已有 3000 多个 star:本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 个人博客项目功能的讲解,通过本课程的学习,不仅仅让你掌握基本的 Spring Boot 开发能力以及 Spring Boot 项目的大部分开发使用场景,同时帮你提前甄别和处理掉将要遇到的技术难点,认真学完这个课程后,你将会对 Spring Boot 有更加深入而全面的了解,同时你也会得到一个大家都在使用的博客系统源码,你可以根据自己的需求和想法进行改造,也可以直接使用它来作为自己的个人网站,这个课程一定会给你带来巨大的收获。作者寄语本课程录制于 2020 年,代码基于 Spring Boot 2.x 版本。到目前为止,Spring Boot 技术栈也有一些版本升级,比如 Spring Boot 2.7 发版、Spring Boot 3.x 版本发布正式版本。对于这些情况,笔者会在本课程实战项目的开源仓库中创建不同的代码分支,保持实战项目的源码更,保证读者朋友们不会学习过气的知识点。课程特色 课程内容紧贴 Spring Boot 技术栈,涵盖大部分 Spring Boot 使用场景。开发教程详细完整、文档资源齐全、实验过程循序渐进简单明了。实践项目页面美观且实用,交互效果完美。包含从零搭建项目、以及完整的后台管理系统和博客展示系统两个系统的功能开发流程。技术栈颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,对于提升你的市场竞争力有一定的帮助。实战项目预览    

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值