關于協議,關于網絡編程,這方面的基礎基本沒有。第一次寫相對底層一點這一塊代碼,是做android上的數據和文件上傳和登陸機制,沒有用httpclient,貌似現在這個也支持文件上傳和cookie機制的。傳輸層的協議我簡單理解就是一個交互信息的規范,目前產品研發需要做自定義協議的實現,主要就是xml和java命令對象的轉換需要,在終端和服務器通過約定的xml轉換成命令對象執行操作,用了Digester和betwixt。轉換器類的參考了ConvetUtils的設計。
2 單元測試
主要采用了spring-test中的一些封裝的類,然后也使用另外的mock框架
1 @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
2 public abstract class SpringTxTestCase extends AbstractTransactionalJUnit4SpringContextTests {
3
4 protected DataSource dataSource;
5
6 @Autowired
7 public void setDataSource(DataSource dataSource) {
8 super.setDataSource(dataSource);
9 this.dataSource = dataSource;
10 }
11
12
13 }
14
mock的一點小應用 (mockito下載 http://www.oschina.net/p/mockito)3
4 protected DataSource dataSource;
5
6 @Autowired
7 public void setDataSource(DataSource dataSource) {
8 super.setDataSource(dataSource);
9 this.dataSource = dataSource;
10 }
11
12
13 }
14
defaultRollback :是否回滾事務
子類需要定義applicationContext文件的位置, 如:
@ContextConfiguration(locations = { "/applicationContext-test.xml" })
public class OMALiteServiceServletTest extends DmBaseTest {
private OMALiteServiceServlet servlet;
private HttpServletRequest req;
private MockHttpServletResponse resp;
@Before
public void setUp() throws Exception {
servlet = new OMALiteServiceServlet() {
@Override
public ServletContext getServletContext() {
return new MockServletContext();
}
};
req = mock(HttpServletRequest.class);
when(req.getRemoteHost()).thenReturn("222.222.222.222");
when(req.getRemotePort()).thenReturn(8888);
resp = new MockHttpServletResponse();
servlet.init();
}
/**
* 客戶端發送了非法報文
*/
@Test
// @Repeat(100)
public void test01() throws Exception {
when(req.getParameter("message")).thenReturn("<status1></status>");
servlet.service(req, resp);
}
/**
* 客戶端第一次發送的不是replace
*/
@Test
public void test02() throws Exception {
when(req.getParameter("message")).thenReturn("<final/>");
servlet.service(req, resp);
}
/**
* 客戶端第一次發送replace,然后發送final
*/
@Test
public void test03() throws Exception {
when(req.getParameter("message")).thenReturn("<replace></replace>").thenReturn("<final/>");
servlet.service(req, resp);
servlet.service(req, resp);
}
/**
* 客戶端第一次發送replace,然后發送alert
*/
@Test
public void test04() throws Exception {
when(req.getParameter("message")).thenReturn("<replace></replace>").thenReturn("<alert></alert>");
servlet.service(req, resp);
servlet.service(req, resp);
}
/**
* 客戶端返回result命令中item和服務器發送的Get命令的item不一致
*/
@Test
public void test05() throws Exception {
final Get get = mock(Get.class);
List list = mock(List.class);
when(list.size()).thenReturn(2);
when(get.getItems()).thenReturn(list);
servlet = new OMALiteServiceServlet() {
@Override
public ServletContext getServletContext() {
MockServletContext sc = new MockServletContext();
OMALiteSession session = mock(OMALiteSession.class);
when(session.getAttribute("first")).thenReturn(false);
when(session.getAttribute("lastCommand")).thenReturn(get);
when(session.getAttribute("visitTime")).thenReturn(System.currentTimeMillis());
sc.setAttribute(OMALiteStatus.BASE_SESSION_KEY + "222.222.222.222:8888", session);
return sc;
}
};
servlet.init();
when(req.getParameter("message"))
.thenReturn(
"<result><item><path>path1</path><value>value1</value><type>type1</type></item><item><path>path2</path><value>value2</value></item><type>type2</type></result>");
servlet.service(req, resp);
}
/**
* ip和port相同才為一個session
*/
@Test
public void test06() throws Exception {
when(req.getParameter("message")).thenReturn("<replace></replace>");
servlet.service(req, resp);
when(req.getParameter("message")).thenReturn("<replace></replace>");
when(req.getRemoteHost()).thenReturn("111.222.222.222"); //更改ip和port模擬另一個用戶訪問
when(req.getRemotePort()).thenReturn(8877);
servlet.service(req, resp);
when(req.getRemoteHost()).thenReturn("222.222.222.222"); //切換到第一個用戶
when(req.getRemotePort()).thenReturn(8888);
when(req.getParameter("message")).thenReturn("<alert></alert>");
servlet.service(req, resp);
}
}
三 JMS
java消息服務。可用于不同服務器之間的消息傳遞。
以前對這一塊的基本沒接觸過,目前了解一些遠程監控都是基于jms消息服務的,還有一些分布式緩存的東西比如Ehcache
JMS 服務器http://activemq.apache.org/
四 異常處理。
異常處理是一個一直很重視但是并沒有怎么處理好且沒仔細體會的話題了。
如果我們用struts2我們知道可以在將所有異常拋給它,然后在配置文件中配置異常對于的視圖。另外spring也有相關的機制。
這一次的編碼沒有用任何框架,用的servlet編寫控制,并分了dao和service層。這里淺談一下自己在編碼中異常處理的一些心得。
1 重視異常。
寫一些測試代碼的時候我們總是習慣catch 異常然后直接打印異常堆棧e.printStackTrace()。但是這在生產環境中是一個很不好的習慣。
我們必須嚴格禁止System.out.println() 和e.printStackTrace()。 出現了異常我們需要兩方面的處理,一是對于開發人員日后追蹤bug做日志記錄,另一方面是對客戶的反饋。
2如何對待異常
當我們catch到異常之后,有2種對待的方式。
a 吞掉異常。在一些對我們整個系統業務并不重要的異常我們可以吃掉,如果需要可以加入一些warn級別的日志。
比如SpringJdbcTemp 中的queryForMap方法,當數據庫記錄為空的時候會拋出一個EmptyResultDataAccessException ,這個異常其實對于我們并不重要,當沒有數據我們返回一個空map不就ok了,所以我們可以catch這個異常然后new 一個HashMap就行。
1 SimpleJdbcTemplate simpleJdbcTemplate = null;
當目前獲取的異常在本層并不想作處理的時候,我們可以包裝成一個新的異常統一到上層做處理。
下面的代碼
這段代碼在servlet之中,dao和service的代碼基本都采用a,b兩條做的處理,都包裝成自定義異常到頂層處理 。注意,一定要做log記錄,resp.sendxx是發生此類異常需要反饋給客戶的東西,而logger.error則是記錄給我們開發人員作bug追蹤的。當我們catch到異常之后,有2種對待的方式。
a 吞掉異常。在一些對我們整個系統業務并不重要的異常我們可以吃掉,如果需要可以加入一些warn級別的日志。
比如SpringJdbcTemp 中的queryForMap方法,當數據庫記錄為空的時候會拋出一個EmptyResultDataAccessException ,這個異常其實對于我們并不重要,當沒有數據我們返回一個空map不就ok了,所以我們可以catch這個異常然后new 一個HashMap就行。
1 SimpleJdbcTemplate simpleJdbcTemplate = null;
2 String sql = null;
3 Map map;
4 try {
5 map = simpleJdbcTemplate.queryForMap(sql);
6 } catch (EmptyResultDataAccessException e1) {
7 map = Maps.newHashMap();
8 }
b 向上拋出異常3 Map map;
4 try {
5 map = simpleJdbcTemplate.queryForMap(sql);
6 } catch (EmptyResultDataAccessException e1) {
7 map = Maps.newHashMap();
8 }
當目前獲取的異常在本層并不想作處理的時候,我們可以包裝成一個新的異常統一到上層做處理。
1 try {
2 return loader.newDigester().parse(new ByteArrayInputStream(lowerLabelMessage.getBytes()));
3 } catch (Exception e) {
4 throw new OMALiteAnalyticException("server message is Illegal,the message is " + message, e);
5 }
c處理異常2 return loader.newDigester().parse(new ByteArrayInputStream(lowerLabelMessage.getBytes()));
3 } catch (Exception e) {
4 throw new OMALiteAnalyticException("server message is Illegal,the message is " + message, e);
5 }
下面的代碼
try {
sendOMALite = receiveOMALite.getCommand().doReceiveHandle(req);
} catch (OMALiteClientException e) {
resp.sendErrorStatus(COMMAND_FAILED,
getCommandNameOfOMALite((OMALite) currentSession.getAttribute("lastOMALite")),
receiveOMALite.getPkgId());
logger.error(e.getMessage(), e);
return;
} catch (OMALiteServerException e) {
resp.sendFinal(receiveOMALite.getPkgId());
logger.error(e.getMessage(), e);
} catch (OMALiteException e) {
resp.sendErrorStatus(COMMAND_FAILED,
getCommandNameOfOMALite((OMALite) currentSession.getAttribute("lastOMALite")),
receiveOMALite.getPkgId());
logger.error("UnKnow Exception", e);
return;
}
sendOMALite = receiveOMALite.getCommand().doReceiveHandle(req);
} catch (OMALiteClientException e) {
resp.sendErrorStatus(COMMAND_FAILED,
getCommandNameOfOMALite((OMALite) currentSession.getAttribute("lastOMALite")),
receiveOMALite.getPkgId());
logger.error(e.getMessage(), e);
return;
} catch (OMALiteServerException e) {
resp.sendFinal(receiveOMALite.getPkgId());
logger.error(e.getMessage(), e);
} catch (OMALiteException e) {
resp.sendErrorStatus(COMMAND_FAILED,
getCommandNameOfOMALite((OMALite) currentSession.getAttribute("lastOMALite")),
receiveOMALite.getPkgId());
logger.error("UnKnow Exception", e);
return;
}
3