首页 > 其他 > 详细

项目技术沉淀0

时间:2019-11-27 21:51:19      阅读:73      评论:0      收藏:0      [点我收藏+]

#项目技术沉淀

#####好久没有更新博客,如今项目的所有功能也基本完成,目前还差的就剩下权限管理那块了。所以,需要博客来将所有的技术,包括各个细小的技术进行沉淀下,做下笔记。

一、公告模块

刚接手项目,对一切需求都是陌生的,首先面对的是公告模块,从最简单的开始——公告,原因是公告不涉及多表的级联查询。

(一)、数据库

首先谈的就是数据库,由于刚开始想的没有那么齐全,所以数据有可能涉及的有些问题。后来新添加了几个需要的字段。根据阿里巴巴的开发手册中的数据库的要求,每个表都需要加入create_time和update_time。阿里巴巴的开发手册可以参考github地址。文末将贴出。
另外,可使用mybatis_generator自动生成各种文件。以下为mybatis代码:

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- mybatis逆向生成xml配置 -->
<generatorConfiguration>
    <properties resource="application.properties" /> <!-- 数据库连接配置文件 -->
    <context id="sqlserverTables" targetRuntime="MyBatis3">
        <!-- 生成的pojo,将implements Serializable-->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 数据库链接URL、用户名、密码(这个就是你的spring boot项目自带的那个配置文件里面的数据库的配置) -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://202.113.127.236:3306/tjikc?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC"
                        userId="${spring.datasource.druid.username}"
                        password="${spring.datasource.druid.password}">
            <property name ="nullCatalogMeansCurrent" value = "true"/>
        </jdbcConnection>

        <!--
            默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer
            true,把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal
        -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!--
            生成model模型,对应的包路径,以及文件存放路径(targetProject),targetProject可以指定具体的路径,如./src/main/java,
            也可以使用“MAVEN”来自动生成,这样生成的代码会在target/generatord-source目录下<br>       (通俗的讲就是你想要把生成的实体类的放到哪里)
        -->
        <!--<javaModelGenerator targetPackage="com.joey.mybaties.test.pojo" targetProject="MAVEN">-->
        <javaModelGenerator targetPackage="cn.tj.entity" targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
            <!-- 从数据库返回的值被清理前后的空格  -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--对应的mapper.xml文件(通俗的讲就是你要把mapper.xml文件放到什么地方去,我是放到resource下一个名叫mappers的文件夹里面了)  -->
        <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 对应的Mapper接口类文件 (通俗的讲就是你要生成的稻城mapper接口的地方 需要根据自己的文件进行配置) -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="cn.tj.mapper" targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 列出要生成代码的所有表,这里配置的是不生成Example文件 -->
        <!-- 这个地方呢 也是你需要自动修改的地方  第一个参数是你数据库的表名  第二个参数就是想要生成实体类的名称  -->
        <table tableName="表名" domainObjectName="映射成为的实体类名" enableCountByExample="true" enableUpdateByExample="true" enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true" >
        </table>
    </context>
</generatorConfiguration>

文件名为generatorConfig.xml,然后可以在maven工程中启动generator插件,当然也需要添加该插件,坐标:

<plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.2</version>
            <configuration>
                <verbose>true</verbose>
                <overwrite>true</overwrite>
                <!--可指定配置文件地址,默认地址resources/generatorConfig.xml -->
                <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <!--<scope>runtime</scope>-->
                    <version>8.0.13</version>
                </dependency>
            </dependencies>
        </plugin>

(二)、代码

1. 前端
    1. 页面设计:
        * 刚开始的一个项目,没有设计目录结构,结果各种html文件,都没有归类好,这就直接导致项目后期维护,包括修改需求的难度。所以在每次前端页面设计的同时,需要对该模块所需要的页面进行一个大概的设计,这其中就包括你所需要的各种url跳转的链接,也就是你controller层的@requestMapping的内容。
        * 首先在导航栏的有超链接的按钮,当点击的时候直接发出请求,请求到controller层,然后遍历数据库中的所有数据,并且返回给modelAndView视图层,将结果集存进去,返回给页面进行遍历。
        * 数据量多的话肯定需要分页,分页选择[datatables](http://www.datatables.club/ "datatables"),里面有很多案例可以直接拿过来用。需要引入各种css和js文件。在这里不再赘述。
        * 关于datatables出现的各种问题:
            * 如果引入后只有表格,没有分页的样式,可以查看bootstrap4有没有引进去。每个datatables都必须经过初始化,这也是一种可能。
            * 以下是初始化和将datatables中文化的代码:
            $('#declarationList').DataTable({
                destroy:true,
                searching:true,
                bAutoWidth:false,
                language: {
                    "sProcessing": "处理中...",
                    "sLengthMenu": "显示 _MENU_ 项结果",
                    "sZeroRecords": "没有匹配结果",
                    "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
                    "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
                    "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
                    "sInfoPostFix": "",
                    "sSearch": "搜索:",
                    "sUrl": "",
                    "sEmptyTable": "表中数据为空",
                    "sLoadingRecords": "载入中...",
                    "sInfoThousands": ",",
                    "oPaginate": {
                        "sFirst": "首页",
                        "sPrevious": "上页",
                        "sNext": "下页",
                        "sLast": "末页"
                    },
                    "oAria": {
                        "sSortAscending": ": 以升序排列此列",
                        "sSortDescending": ": 以降序排列此列"
                    }
                }
            });
            declarationList是table表的id,destory的作用是摧毁一个datatables,新创建一个datatables。总之,如果你复写搜索的话,必须加这个,如果不加,会直接报错。searching:datatables自带的搜索框。language:更改中文用的。另外,如果你要是复写了datatables的查询结果,则必须行列值必须对应,这就意味着你不能对th元素或者td元素进行hidden属性。否则报错。具体报错自己尝试。

公告中心的界面
技术分享图片

2. 后台

    1. 新增:
        采用模态框的形式进行用户交互:呈简洁性交互。

添加公告界面
技术分享图片

        另外,模态框有点问题,背景颜色太深,具体原因没有深究,但是后面的都没有问题。具体模态框的使用代码可以参考

模态框的使用

        所有的数据应当在前端就应该控制了,例如用户传入的数据为空。在后台之后,就应该将所有的数据进行传输,而不进行判断了。具体前台判断用户传入数据为空需要用到validate插件。具体查看

"validate插件——jquery"

        代码例子:
            html:
                <form id="saveNoticeForm"   method="post">
            <@shiro.user>
            <input id="addUserName" name="addUserName" class="form-control" type="hidden" value="${currentUser.username}">
            </@shiro.user>
            <div class="modal-content">
                <div class="modal-header">
                    <div class="row container-fluid">
                        <label for="addNoticeTitle">
                            <h5 class="modal-title">公告标题:</h5>
                        </label>
                        <input name="addNoticeTitle" id="addNoticeTitle" style="width:69%;" type="text" class="form-control" placeholder="请输入公告标题">
                    </div>
                </div>
                <div class="modal-body">
                    <!--公告内容-->
                    <span>
                        <label for="addNoticeContent"></label><textarea id="addNoticeContent" name="addNoticeContent"  rows="20" style="width: 100%; height: 100%;margin-top: -30px;" class="form-control"  placeholder="请在这里输入公告内容"></textarea>
                    </span>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal" id="closeDialog">取消</button>
                    <button type="submit" class="btn btn-primary" id="btn_save" name="add">确定</button>
                </div>
            </div>
        </form>

            js:
            $("#saveNoticeForm").validate({
                rules:{
                    addNoticeTitle:{
                        required:true,
                        minlength: 1
                    },
                    addNoticeContent:{
                        required:true,
                        minlength: 1
                    }
                },
                messages:{
                    addNoticeTitle:{
                        required:"请输入公告标题",
                        minlength:"公告标题至少包含一个字"
                    },
                    addNoticeContent:{
                        required:"请输入公告内容",
                        minlength:"公告内容至少包含一个字"
                    }
                }
            });
            作用:如果想要使用validate必须要使用form向后台传送数据,rules:拦截规则,输入框的内容必须用label包裹,否则出不来样式。required:必填项,如果用户没有填写,直接拦截。minlength:最短长度,不满足直接拦截。
            message:表示出错的情况需要展示的信息。
        然后使用js向后台进行发出请求。由于需要用户的信息,所以需要判断用户是否登录,如果用户没有登陆提示用户登录后进行添加公告。如果用户登录了,则使用ajax进行传输数据。回调函数为更新成功提示信息。正常存入公告。需要说明的是:如果正常访问到dao层,但是取到的数据都是为null或者是有某个字段为null,多半是因为你属性映射失败。有两种解决方案:
            1. 可以采用基于注解的进行映射。
                代码:
            @Select("select mes_id as mesId,mes_name as mesName,mes_contents as mesContents,mes_createTime as mesCreateTime,mes_creator as mesCreator from message")
            List<Message> findAllNotice();
            这样的形式也可以进行另一种方式:
            @Select("SELECT * FROM problem WHERE app_id = #{appId}")
            @Results(id="problemMap",value = {
                @Result(id = true,column = "132132", property = "1321", jdbcType = JdbcType.INTEGER, javaType = Integer.class),
                @Result(column = "12321", property = "1321", jdbcType = JdbcType.VARCHAR, javaType = String.class),
                @Result(column = "321321", property = "13213", jdbcType = JdbcType.VARCHAR, javaType = String.class),
        })
            List<Problem> selectByAppId(Integer appId);
            column表示是数据库的属性名,property是实体类的对应的名字,形成映射关系。
            2. 可以采用xml的方式:
                <resultMap id="BaseResultMap" type="cn.tj.entity.Message" >
                <id column="mes_id" property="mesId" jdbcType="INTEGER" />
                <result column="mes_name" property="mesName" jdbcType="VARCHAR" />
                <result column="mes_contents" property="mesContents" jdbcType="VARCHAR" />
                <result column="mes_createTime" property="mesCreateTime" jdbcType="VARCHAR" />
                <result column="mes_creator" property="mesCreator" jdbcType="VARCHAR" />
              </resultMap>

    2. 修改:
        修改的话,当点击按钮的时候,进入js方法,执行两次post请求,第一次的请求是将数据展示待模态框内,然后如果请求成功的话,会在回调函数内进行执行两个主要过程,第一:将查询到的数据,放到模态框内进行展示,第二:展示的内容要求可以被修改,这就要求,必须是input框或者textarea,然后当点击模态框的确认按钮的时候,判断用户是否进行登录,如果登录,则发送第二次的post请求(ajax),将修改的内容传到后台。在这里,前台代码有点不好,没有进行查询用户是否输入内容,所以在后台进行了处理,进行了抽离了方法:
            private int mesStr (String mesName,String mesContent){
                if (mesName==null||"".equals(mesName)){
                    return 1;
                }else if (mesContent==null||"".equals(mesContent)){
                    return 2;
                }else{
                    return 3;
                }
            }
        返回值1表示公告的标题为空,返回值为2表示内容为空,返回值为3表示其他情况。
        还需要一提的是:怎样传输变量给请求,比如想查询id为1的公告所有信息,如何发送post请求:
            $.post("/updateOneNotice/" + mesId,{},function(){});这是整个过程,那么问题又来了,后台如何接受?
            后台的接受过程:
                @RequestMapping("/displayOneNotice/{mesId}")
                @ResponseBody
                public Map<String,Object> displayOneNotice(@PathVariable("mesId") Integer mesId) {
                    Map<String,Object> returnMap=new HashMap<>();
                    System.out.println(mesId);
                    Message message = noticeService.findById(mesId);
                    System.out.println(message);
                    returnMap.put("message",message);
                    return returnMap;
                }
                需要提示的是:如果你希望给用户提示,就使用js的方式进行传输数据,但是如果你不需要进行提示用户,或者需要想后台传输的数据量太多,则可以采用form表单,使用这种方式的缺点是不能给用户反馈。这个很容易理解。最后,如果你希望前台(浏览器)获得回调函数,则必须要@ResponseBody注解。
        接着刚才的说,如果返回值为3,则进行更新,由于需要更新时间,就需要对时间进行格式化:
         //格式化时间
        SimpleDateFormat sdf=new SimpleDateFormat();
        sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
        Date date=new Date();
        sdf.format(date)

修改的界面
技术分享图片


    3. 删除

删除的某个图片
技术分享图片
--------------
先post一张照片,来展示缺点,影响用户体验度,当用户点击提交的时候,应当给用户提示,是否删除?如果点确定的话,则删除。否则容易造成误删,影响用户体验度。
删除的功能:在删除的button上进行定义方法,并将隐藏域中的公告id传进来。然后向后台传送id,也可以这样传:不用通过url的地址进行传送,而是将数据封装成为json数据传送:
function deleteNotice(mesId) {
//获取到notice的id
$.post("/deleteNotice", {
mesId: mesId,
}, function (data) {
alert(mesId + "删除成功");
//需要跳转到http://localhost:8080/messageMain

        // 1、获取当前全路径,如: http://localhost:8080/springmvc/page/frame/test.html
        var curWwwPath = window.location.href;
        // 获取当前相对路径: /springmvc/page/frame/test.html
        var pathName = window.location.pathname;    // 获取主机地址,如: http://localhost:8080
        var local = curWwwPath.substring(0, curWwwPath.indexOf(pathName));
        // 获取带"/"的项目名,如:/springmvc
        var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
        var rootPath = local + projectName;
        window.location.href = pathName;
    })
}
    4. 显示
    显示也没有什么难点,基本思路就是想后台传送查询的公告id,返回给页面,进行展示/具体界面跟上述一样。

其他待总结:

freemarker语法,包括list,if,空字符串的判断。

以上为公告的基本总结。供以后参考使用。
具体还有什么注意点,在后面的文章中接着分析,下一个为认证案例管理

项目技术沉淀0

原文:https://www.cnblogs.com/chenyameng/p/11945564.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!