• 项目技术沉淀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="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=" 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,空字符串的判断。
    

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

    博客网站 https://yamon.top 个人网站 https://yamon.top/resume GitHub网站 https://github.com/yamonc 欢迎前来访问
  • 相关阅读:
    nginx syslog 配置
    通过granfana 以及prometheus 比较zulu 、oracle、openjdk 等jvm 运行
    cube.js 新版本试用preosto
    关于redash 自定义可视化以及query runner 开发的几篇文章
    通过redash query results 数据源实现跨数据库的查询
    cube.js 最近版本的一些更新
    zeebe 0.20.0 集群部署试用
    redash oracle 数据源docker 镜像
    使用jmx-exporter&&jmxtrans && nexus jmx 暴露nexus 系统指标信息
    jmxtrans docker-compose 运行
  • 原文地址:https://www.cnblogs.com/chenyameng/p/11945564.html
Copyright © 2020-2023  润新知