项目技术沉淀


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

一、公告模块

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

(一)、数据库

首先谈的就是数据库,由于刚开始想的没有那么齐全,所以数据有可能涉及的有些问题。后来新添加了几个需要的字段。根据阿里巴巴的开发手册中的数据库的要求,每个表都需要加入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,空字符串的判断。

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

 posted on 2019-11-27 21:20  ben跑的换行符  阅读(413)  评论(0编辑  收藏  举报