Java开发项目实例中的技术总结

来源:互联网 发布:检查80端口 编辑:程序博客网 时间:2024/05/22 09:48

一:前端的请求参数如下图所示:

此时后台的处理方法为:直接使用request接受这个参数,通过JSON工具类转换成对应的对象即可获取对应的值,这种后台处理的方式适用于上图中的Query String Parameters


二:前端的请求参数如下所示:与上图不同的是,请求的参数格式为红圈中所标记的,后台如果采取request.getParameter的方式获取也是不行的,(笔者通过@requestBody这个标签也是没获取到,不知道是不是使用的spring3的缘故)


处理方法如下:通过ServletInputStream输入流的方式,将前端的请求参数传递到后台中,转换成对应的String字符串,就跟案例一中的类似了。下面是输入流的代码片段,最后的图片是json转换成对象

public static String getStringFromStream(HttpServletRequest req) {        ServletInputStream is;        try {            is = req.getInputStream();            int nRead = 1;            int nTotalRead = 0;            byte[] bytes = new byte[10240];            while (nRead > 0) {                nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);                if (nRead > 0)                    nTotalRead = nTotalRead + nRead;            }            String str = new String(bytes, 0, nTotalRead, "utf-8");            is.close();            return str;        } catch (IOException e) {            e.printStackTrace();            return "";        }    }

后台Contoller的处理方法为:List中存放的是String字符串的键值对映射的对象。(拿到字符串后,有很多种方法处理,提取参数,这里我选择的是阿里巴巴开源的JSON处理方式,其他的各位小伙伴可以自行尝试,最好分享一下哦大笑)。



三:(跨域)做过跨越多个网站的Ajax开发的朋友都知道,如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。Ajax的跨域访问问题是现有的Ajax开发人员比较常遇到的问题。
处理方式:①前端请求的时候需要设置允许跨域请求,具体如何实施的(我不是前端,不太了解,自行百度哈),对于后台是这样处理的,配置一个过滤器即可(实现Filter接口)。过滤指定url的请求。允许该请求跨域。代码如下

public class AjaxFilter implements Filter{    private static Logger logger = LoggerFactory.getLogger(AjaxFilter.class);    public AjaxFilter() {        super();    }    @Override    public void init(FilterConfig filterConfig) throws ServletException {        logger.info("跨域请求过滤器启动");    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        HttpServletResponse httpServletResponse=(HttpServletResponse)servletResponse;        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");        httpServletResponse.setHeader("Access-Control-Max-Age", "2592000");        httpServletResponse.setHeader("Access-Control-Allow-Headers", "authToken,content-type");        httpServletResponse.setHeader("Access-Control-Allow-Methods","POST, GET");        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");        httpServletResponse.setContentType("text/html;charset=utf-8");        filterChain.doFilter(servletRequest,httpServletResponse);    }    @Override    public void destroy() {    }}
四:数据库中时间转换(oracle数据库),发送该事件的环境为:页面的请求是String类型的时间,并且只有年月日,而数据库的时间为SYSDATE类型的。包含了时间分钟秒,如何进行时间上的匹配呢。
处理方法:

<select id="queryMessageCount" resultType="Integer" parameterType="HashMap">        SELECT  count(RECORD_ID) FROM COM_T_SMS_RECORD a        LEFT JOIN COM_T_USER b ON B.USER_ID= A.SENDER        <where>            <if test="messageType!=null and messageType!=''">                a.MESSAGE_TYPE=#{messageType}            </if>            <if test="phoneNo!=null and phoneNo!=''">                and a.sende_phone like concat(concat('%',#{phoneNo}),'%')            </if>            <if test="sendTime!=null and sendTime!=''">                AND substr(TO_CHAR(a.send_time,'yyyy-MM-DD HH:mm:SS'),0,10)=#{sendTime}            </if>            <if test="senderName!=null and senderName!=''">                and a.sender =(select user_id from com_t_user where user_name=#{senderName})            </if>            <if test="caseNo!=null and caseNo!=''">                and a.send_message like concat(concat('%',#{caseNo}),'%')            </if>            <if test="exclude!=null and exclude!=''">                a.MESSAGE_TYPE!=#{exclude}            </if>        </where>    </select>
五:前端输入的form表单中提交后后台接受时中文出现乱码情况
处理方式:

  sendUserName = java.net.URLDecoder.decode(sender, "UTF-8");

六:数据库中的分页操作(oracle数据库)
处理案例:

<select id="queryAppInfos" resultMap="AppInfos">        SELECT p.* FROM (select DISTINCT rownum as r,b.user_name,a.user_id,a.android_version,a.app_version,        substr (a.phone_no,4) as phone_no,a.record_time,a.camera_version from com_t_app_version a        inner join com_t_user b on a.user_id= b.user_id        <where>            <if test="userName!=null and userName!=''">                b.user_name like concat(concat('%',#{userName}),'%')            </if>            <if test="phoneNo!=null and phoneNo!=''">                and a.phone_no like concat(concat('%',#{phoneNo}),'%')            </if>            <if test="departId!=null and departId!=''">                and b.depart_id=#{departId}            </if>            and <![CDATA[ rownum <= #{pageEnd}]]>        </where>        ORDER BY record_time desc) p        where  <![CDATA[ r> #{pageStart}]]>    </select>

简单解释一下:这种分页的效率比使用between and高,原因就是between是查询出来后再进行分页筛选。导致效率慢。这种方式是分页查询出来后再进行分页。效率明显高。因为不需要检索全文,只要在小于最大页数的结果集中进行筛选即可。
基本的思路就是:将rownum作为一个字段显示在结果集中,而后在结果集中继续筛选,上述蓝色的字体代表的是结果集,红色字体代表的是分页的开始行数和结束行数。

七:数据库分页查询不重复的数据(数据库中包含有重复的数据),当然也可以使用应用程序进行去重操作。本人习惯于查询的时候去重。
处理方法事例:包括数据库中varchar2类型时间的处理,和分页的处理,模糊查询,思路就是将要查的数据单独的作为一个子查询,然后再用rownum进行查询,与查询的数据进行合并,同时进行分页处理(小于最大的行数),将查询的结果再一次当作一个子查询模块进行分页筛选(大于最小的行数)

select id="queryAllTaskByApp" parameterType="HashMap" resultMap="Task">        select * from (select rownum as r,p.* from (select DISTINCT a.task_id,a.task_status,        c.case_no,c.car_id,a.create_time from sm_t_task a        left join sm_t_taskcase_relation b on a.task_id = b.task_id        left join sm_t_case c on b.case_id = c.case_id        <where>            a.is_delete=1            <if test="userName != null and userName != ''">                and a.task_id in (select distinct x.task_id from sm_t_schedu_user_rel y                left join sm_t_task_record x on x.user_id=y.front_user_id                left join com_t_user z on z.user_id=y.front_user_id                where z.user_name like concat(concat('%',#{userName}),'%'))            </if>            <if test="followType!=null and followType!=''">                and a.follow_type=#{followType}            </if>            <if test="taskType !=null and taskType!=''">                and a.task_status=#{taskType}            </if>            <if test="caseNo!=null and caseNo!=''">                and c.case_no like concat(concat('%',#{caseNo}),'%')            </if>            <if test="startTime != null and startTime != ''">                <![CDATA[ and to_date(substr(a.create_time,1,10), 'yyyy-MM-dd')  >= to_date(#{startTime}, 'yyyy-MM-dd')]]></if>            <if test="endTime != null and endTime != ''">                <![CDATA[ and to_date(substr(a.create_time,1,10), 'yyyy-MM-dd') <= to_date(#{endTime}, 'yyyy-MM-dd')]]></if>            and c.case_no is not null and c.car_id is not null        </where>        order by a.create_time desc)p)        where  <![CDATA[ r >= #{startPage}]]>  and  <![CDATA[ r <= #{endPage}]]>    </select>

八:页面的表格显示,效果图如下:由于发送信息的内容较长,所以这里使用了隐藏的方法,超过单元格的内容通过“...”代替,鼠标放在单元格上就会出现图中画圈所示的内容,即完整的内容


此页面分为两个模块,一个是form表单提交和重置,一个是查询显示的数据。

form表单不作过多说明。这个简单的很,着重说一下这数据的展示效果。这单元格的展示采用的是EasyUI中的datagrid,链接为:http://www.jeasyui.net/plugins/183.html

尤其关注的是列的属性。下面的代码块为页面的部分核心代码。蓝色的部分为显示的数据展示的部分,褐色部分为验证输入代码,其余紫色部分为辅助性的代码,红色部分为单元格显示的Div和样式,(客户那边竟然还是IE8浏览器,很多隐藏不兼容,只能想到这个字符串截取的方法显示了)

define([    'jquery',    'underscore',    'backbone',    'page',    /*'text!templates/general/device.html',*/    'text!' + BASE_APP.path + '/system/message.do'], function ($, _, Backbone, Page, tmpl) {    return Page.view({        template: _.template(tmpl),        start: start    });    function start() {        var self = this,            wrap = self.$el;        // 解析页面插件        $.parsePlugins(wrap);        // 查询        $.numberCheck();        self.$('#S_search').on('click', function () {            var name = $('[name="sender"]').val(),                phone = $('[name="phoneNo"]').val();            var m = $('[name="module"]').val();            var ms = $('[name="messageType"]').val();            if (name && !$.checkName(name)) {                $.tips({                    content: "请输入正确的姓名!"                });            } else if (phone && !$.checkPhone('[name="phoneNo"]')) {                $.tips({                    content: "请输入一个正确的手机号码!"                });            } else if ((m === "1" && ms === "5") || ((m === "2" && ms === "1")                    || (m === "2" && ms === "2") || (m === "2" && ms === "3")                    || (m === "2" && ms === "4"))) {                $.tips({                    content: "选择的短信模块和短信类型不匹配!"                });            }            else {                var params = $.formQueryParams('[name=form-message]');                $('#messageList').datagrid('load', params);            }            return false;        });        // 重置表单        $('[name=form-messgae]').form();        self.$('#S_reset').on('click', function () {            $('[name=form-message]').form('clear');            return false;        });        // 列表        $('#messageList').datagrid({            url: BASE_APP.path + '/queryMessage.do',            method: 'post',            fitColumns: true,            singleSelect: true,            rownumbers: true,            pagination: true,            multiSort: true,            nowrap: true,            columns: [                [{                    field: 'addressee',                    title: '收件人',                    sortable: true,                    width: 37,                    formatter: function (value) {                        if(value.length>=17) {                            return '<div title="' + value + '" style=" width:16em;' +                                '    position:relative;' +                                '    line-height:1.4em;' +                                '    height:1.4em;' +                                '    overflow:hidden;">' + value.substring(0,14)+"..."+ '</div>';                        }                        else {                            return value;                        }                    }                },                    {                        field: 'module',                        title: '短信模块',                        width: 14,                        sortable: true                    },                    {                        field: 'messageType',                        title: '短信类型',                        width: 15,                        sortable: true                    },                    {                        field: 'sendMessage',                        title: '发送信息',                        sortable: true,                        width: 70,                        formatter: function (value) {                            if(value.length>=30) {                                return '<div title="' + value + '" style=" width:30em;' +                                    '    position:relative;' +                                    '    line-height:1.4em;' +                                    '    height:1.4em;' +                                    '    overflow:hidden;">' + value.substring(0,30)+"..."+ '</div>';                            }                            else {                                return value;                            }                        }                    },                    {                        field: 'returnMessage',                        title: '返回信息',                        sortable: true,                        width: 70,                        formatter: function (value) {                            if(value.length>=30) {                            return '<div title="' + value + '" style=" width:30em;' +                                '    position:relative;' +                                '    line-height:1.4em;' +                                '    height:1.4em;' +                                '    overflow:hidden;">' + value.substring(0,30)+"..."+ '</div>';                            }                            else {                                return value;                            }                        }                    },                    {                        field: 'sendTime',                        title: '发送时间',                        sortable: true,                        width: 28                    },                    {                        field: 'messageStatus',                        title: '发送状态',                        sortable: true,                        width: 27,                        formatter: function (value, row, index) {                            return formatStatus(value, false);                        },                        styler: function (value, row, index) {                            return formatStatus(value, true);                        }                    }                ]            ],            loadFilter: function (data) {                return {                    total: data.returnObject.pageMsg.totalNum,                    rows: data.returnObject.messageInfos                }            },            onLoadSuccess: function () {                $.datagridResize('#messageList'); // 列表重置大小事件            }        });    }    //格式化状态    function formatStatus(num, styler) {        var status, cls;        switch (num) {            case "2":                status = "发送成功";                cls = {                    cls: 'text-status text-success'                };                break;            case "3":                status = "发送失败";                cls = {                    cls: 'text-status text-danger'                };                break;            case "1":                status = "正在发送";                cls = {                    cls: 'text-status text-primary'                };                break;        }        if (styler) {            return cls;        }        return status;    }});

九:采用注解的方式获取配置文件中的值

处理方法:

①:配置文件如下图所示,获取三个值分别是灰色部分所示。
②:在配置文件xml中增加bean配置如下所示(至于maven依赖的包,如若报错的话,可以百度依赖的jar包是什么。这个bean可以配置在db配置的所在xml中)

<!--创建properties工厂--><bean id="properties"  class="org.springframework.beans.factory.config.PropertiesFactoryBean"><property name="locations"><list><value>classpath:config.properties</value></list></property></bean>

③:在需要获取配置文件的类中添加注解的格式如下,这三步完成的话,就可以直接在类中引用变量的值了。很方便哦。

 @Value("#{properties[filepath]}")    private String filePath;    @Value("#{properties[uploadPath]}")    private String uploadPath;

十:采用注解的方式开启事务,事务生成的条件

处理方法:

①:配置文件中配置相关的注解,开启事务如下图所示:


②:在需要开启注解的方式上增加注解,需要注意是:默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚, “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常” 。简单的说:如下图红框中的内容,设置一下就会对检查型异常进行回滚,(其实可以不设置,检查型异常都会报错的),还有就是,在catch中异常的时候,要对异常重新抛出才可以让事务生效,即 throw new  RuntimeException(“事务回滚了”);

十一:sql语句中传人的是List集合的处理方法,请求的参数未list。

List<User> getUserListByUserIds(List<String> userIds);
xml中的sql对应部分为

<foreach collection="list" item="item" open="(" close=")" separator=",">    #{item}</foreach>

还有另外的一种情况:

List<Area> queryArea(@Param("departId") List<String> departId);
此时如果list的集合是空,可采用如下判断,而且请求的参数采用HashMap的形式进行,departId,如果是数组的话直接是数组的属性.length>0,传进来的是一个集合,故而是departId.size>0.

<select id="queryArea" resultType="com.wisemax.common.dto.area.Area" parameterType="HashMap">    select b.depart_name as areaName,b.depart_id as areaId FROM COM_T_AREA a    LEFT JOIN com_t_depart b on a.area_id = b.area_id    <where>        <if test="departId!=null and departId.size()>0">            depart_id in            <foreach collection="departId" item="item" open="(" close=")" separator=",">                #{item}            </foreach>    </if>    </where>    ORDER by sort_id asc