zoukankan      html  css  js  c++  java
  • 项目技术沉淀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 欢迎前来访问
  • 相关阅读:
    UVA 10618 Tango Tango Insurrection
    UVA 10118 Free Candies
    HDU 1024 Max Sum Plus Plus
    POJ 1984 Navigation Nightmare
    CODEVS 3546 矩阵链乘法
    UVA 1625 Color Length
    UVA 1347 Tour
    UVA 437 The Tower of Babylon
    UVA 1622 Robot
    UVA127-"Accordian" Patience(模拟)
  • 原文地址:https://www.cnblogs.com/chenyameng/p/11945564.html
Copyright © 2011-2022 走看看