Java開發專案例項中的技術總結
一:前端的請求引數如下圖所示:
此時後臺的處理方法為:直接使用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