IntelliJ IDEA 2018.3新建SpringBoot项目的流程如下:
分类: IntelliJ IDEA
IDEA 全称 IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手,代码自动提示,重构,J2EE支持、各类版本工具(git,svn,github等),JUnit,CVS整合,代码分析,创新的GUI设计等方面的功能可以说是超常的。IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。它的旗舰版本还支持HTML,CSS,PHP,MySQL,Python等。免费版只支持Java等极少数语言。
macOS Catalina(10.15.4)/IntelliJ IDEA 2018.3/Tomcat 9.0.33/Maven项目调试报错"Caused by: java.util.zip.ZipException: zip file is empty"
macOS Catalina(10.15.4)/IntelliJ IDEA 2018.3/Tomcat 9.0.33/Maven项目调试时报错,这个项目以前是可以正常调试的,一段时间之后,就不能正常调试之下了。
Ubuntu 16.04下创建IntelliJ IDEA图标快捷方式
一般在安装目录下面或者桌面上创建文件,命名为:idea.desktop
使用vim
编辑该文件
1 |
$ vim idea.desktop |
内容如下:
1 2 3 4 5 6 7 8 |
[Desktop Entry] Name=IntelliJ IDEA Comment=IntelliJ IDEA Exec=/home/longsky/Application/idea-IU-163.7743.44/bin/idea.sh Icon=/home/longsky/Application/idea-IU-163.7743.44/bin/idea.png Terminal=false Type=Application Categories=Developer; |
接着给予这个文件执行权限
1 |
$ chmod +x idea.desktop |
以后双击这个图标,就可以直接启动IntelliJ IDEA
了。
IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE,sockjs-1.1.1,stomp-1.2搭建基于Tomcat-7.0.68的WebSocket应用
接着上文IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE搭建基于Tomcat-7.0.68的WebSocket应用
上文的最后我们说到,WebSocket
是需要定时心跳的,否则会在一段时间后自动断开连接,而更重要的是,不是所有的浏览器都支持WebSocket
,早期的IE 10
之前的版本就是不支持的,而这一部分的设备其实是不算少的,而sockjs
的出现,恰恰好来解决了这个问题。对于不支持WebSocket
的浏览器,sockjs
使用了多种方式来兼容这种情况,包括使用长轮询等方式,Spring
更是内建支持这种方式。
下面我们看如何在上篇文章的基础上,增加对于sockjs
的支持。
首先是STOMP
的文档官网地址 http://stomp.github.io/
代码的地址为https://github.com/jmesnil/stomp-websocket,项目下面的lib/stomp.js
就是我们想要的文件。也可以本站下载stomp.js.zip
接下来sockjs
的代码地址https://github.com/sockjs/sockjs-client,项目下面的dist/sockjs-1.1.1.js
就是我们想要的文件。也可以本站下载sockjs-1.1.1.js.zip
接下来我们把下载到的文件放到我们工程目录下面的web
->resources
->javascript
目录下面,如下图:
接下来,添加我们需要的com.fasterxml.jackson.core:jackson-annotations:2.8.1
,com.fasterxml.jackson.core:jackson-core:2.8.1
,com.fasterxml.jackson.core:jackson-databind:2.8.1
这三个jar
包,增加的方式参照上一篇中对于javax.servlet:javax.servlet-api:3.1.0
的操作方法。与上一篇的操作不同的是,这次添加的三个jar
包,都要放到编译完成后的War
包中。最后的结果如下图:
下面,我们开始进行代码的操作,我们在上篇文章中的src
->Tools
->WebSocket
中新增两个源代码文件SockJsController.java
,WebJsSocketConfig.java
.如下图:
其中的代码如下:
SockJsController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package Tools.WebSocket; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Controller; @Controller public class SockJsController { @MessageMapping("/hello") @SendTo("/hello/subscribe") /*貌似这个名字可以随意的,主要用在stomp.subscribe时候的名字*/ public String Hello(String message) throws Exception { return new String("Hello"); } } |
WebJsSocketConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package Tools.WebSocket; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; @Configuration @EnableWebSocketMessageBroker public class WebJsSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.setApplicationDestinationPrefixes("/webSocketServer"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/hello").setAllowedOrigins("*").withSockJS(); } } |
然后修改WebSocket.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)</title> <style type="text/css"> #connect-container { float: left; width: 400px } #connect-container div { padding: 5px; } #console-container { float: left; margin-left: 15px; width: 400px; } #console { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; } </style> <script src="./resources/javascript/sockjs-1.1.1.js"></script> <script src="./resources/javascript/stomp.js"></script> <script type="text/javascript"> var ws = null; var url = null; var transports = []; var stompClient = null; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('echo').disabled = !connected; } function connect() { if (!url) { alert('Select whether to use W3C WebSocket or SockJS'); return; } ws = (url.indexOf('sockjs') != -1) ? new SockJS(url,undefined, {transports: transports}) : new WebSocket(url); if((url.indexOf('sockjs') != -1)) { stompClient = Stomp.over(ws); stompClient.connect({}, function(frame) { setConnected(true); log('Connected: ' + frame); stompClient.subscribe('/hello/subscribe', function(message){ log(message.body); }); }); }else { ws.onopen = function () { setConnected(true); log('Info: connection opened.'); }; ws.onmessage = function (event) { log('Received: ' + event.data); }; ws.onclose = function (event) { setConnected(false); log('Info: connection closed.'); log(event); }; } } function disconnect() { if (ws != null) { ws.close(); ws = null; } stompClient = null; setConnected(false); } function echo() { if(stompClient != null){ var message = document.getElementById('message').value; stompClient.send("/webSocketServer/hello", {}, message); log('Sent: ' + message); }else { if (ws != null) { var message = document.getElementById('message').value; log('Sent: ' + message); ws.send(message); } else { alert('connection not established, please connect.'); } } } function updateUrl(urlPath) { if (urlPath.indexOf('sockjs') != -1) { url = urlPath; document.getElementById('sockJsTransportSelect').style.visibility = 'visible'; } else { if (window.location.protocol == 'http:') { url = 'ws://' + window.location.host + urlPath; } else { url = 'wss://' + window.location.host + urlPath; } document.getElementById('sockJsTransportSelect').style.visibility = 'hidden'; } } function updateTransport(transport) { transports = (transport == 'all') ? [] : [transport]; } function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; } </script> </head> <body> <noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript> <div> <div id="connect-container"> <input id="radio1" type="radio" name="group1" onclick="updateUrl('/webSocketServer');"> <label for="radio1">W3C WebSocket</label> <br> <input id="radio2" type="radio" name="group1" onclick="updateUrl('/webSocketServer/sockjs/hello');"> <label for="radio2">SockJS</label> <div id="sockJsTransportSelect" style="visibility:hidden;"> <span>SockJS transport:</span> <select onchange="updateTransport(this.value)"> <option value="all">all</option> <option value="websocket">websocket</option> <option value="xhr-polling">xhr-polling</option> <option value="jsonp-polling">jsonp-polling</option> <option value="xhr-streaming">xhr-streaming</option> <option value="iframe-eventsource">iframe-eventsource</option> <option value="iframe-htmlfile">iframe-htmlfile</option> </select> </div> <div> <button id="connect" onclick="connect();">Connect</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button> </div> <div> <textarea id="message" style="width: 350px">Here is a message!</textarea> </div> <div> <button id="echo" onclick="echo();" disabled="disabled">Echo message</button> </div> </div> <div id="console-container"> <div id="console"></div> </div> </div> </body> </html> |
最后,我们修改web
->WEB-INF
->web.xml
,在其中增加
1 2 3 4 |
<servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/webSocketServer/sockjs/*</url-pattern> </servlet-mapping> |
修改后的最终结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <filter> <filter-name>struts2</filter-name> <filter-class>Tools.Filter.StrutsPrepareAndExecuteFilterEx</filter-class> <async-supported>true</async-supported> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/webSocketServer/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/webSocketServer/sockjs/*</url-pattern> </servlet-mapping> </web-app> |
参考链接
使用junit测试IntelliJ IDEA 2016.2建立的maven项目
在maven project
项目中引入junit
插件并不困难,只需要在pom.xml
中配置好依赖包即可(IDE
环境下,依赖项会自动生成)。另外,test
类文件需要按照/src/main/java/
的文件结构(main
改为test
)。
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>test</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!--junit 的版本--> <junit.version>4.12</junit.version> </properties> <dependencies> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </project> |
如下图:
IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE搭建基于Tomcat-7.0.68的WebSocket应用
先参照 IntelliJ IDEA 2016.1建立Strut2工程并使用Tomcat调试建立新的工程,一步一步操作,包括最后引用Spring
框架部分。
经过上面的操作,Spring-WebSocket
的包应该已经被默认引入了,如下图所示:
这就意味着我们已经不需要再进行过多的额外配置了。
接下来,我们在src
->Tools
下面新建一个WebSocket
的目录,里面创建三个Java
文件。如下图:
每个文件中的代码如下:
SystemWebSocketHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
package Tools.WebSocket; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; public class SystemWebSocketHandler extends TextWebSocketHandler { private static final ArrayList<WebSocketSession> users = new ArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("ConnectionEstablished"); users.add(session); session.sendMessage(new TextMessage("connect")); session.sendMessage(new TextMessage("new_msg")); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { System.out.println("handleMessage" + message.toString()); session.sendMessage(new TextMessage(new Date() + "")); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if(session.isOpen()){ session.close(); } users.remove(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { users.remove(session); } @Override public boolean supportsPartialMessages() { return false; } /** * 给所有在线用户发送消息 * * @param message */ public void sendMessageToUsers(TextMessage message) { for (WebSocketSession user : users) { try { if (user.isOpen()) { user.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } } } |
WebSocketConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package Tools.WebSocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebMvc @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(systemWebSocketHandler(), "/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor()); } @Bean public WebSocketHandler systemWebSocketHandler() { return new SystemWebSocketHandler(); } } |
WebSocketHandshakeInterceptor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package Tools.WebSocket; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; import java.util.Map; public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { System.out.println("beforeHandshake"); return true; } @Override public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { System.out.println("afterHandshake"); } } |
由于我们使用了Struts2
导致我们的网络请求优先被Struts2
的拦截器拦截,而Struts2
又处理不了websocket
请求,结果直接返回了404
错误。因此我们需要替换掉默认的在web.xml
中定义的Struts2
的拦截器,要求Struts2
不处理websocket
请求。
我们在src
->Tools
下面新建一个Filter
的目录,下面创建一个名为StrutsPrepareAndExecuteFilterEx.java
的源代码文件,如下图:
具体的代码如下:
StrutsPrepareAndExecuteFilterEx.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package Tools.Filter; import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class StrutsPrepareAndExecuteFilterEx extends StrutsPrepareAndExecuteFilter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filter) throws IOException, ServletException { String requestURI = ((HttpServletRequest) req).getRequestURI(); if(requestURI != null && (requestURI.contains("/webSocketServer")) || requestURI.startsWith("ws://") || requestURI.contains("/mspjapi")) filter.doFilter(req, resp); else super.doFilter(req, resp, filter); } } |
这时候的代码是无法编译通过的,原因是依赖的javax
的Jar
包不存在。此时,我们需要手工引入javax.servlet:javax.servlet-api:3.1.0
这个Jar
包。如下图:
还要注意,刚刚添加进入的javax.servlet:javax.servlet-api:3.1.0
这个Jar
包,我们只在编译期间使用,在运行时候,使用Tomcat
自己实现的那个同名Jar
包。也就是这个包是个Provided
,而不是Compile
关系,具体如下图:
接下来,修改web.xml
指定Struts2
的拦截器为我们定义的拦截器
1 2 3 4 5 6 7 8 |
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
修改为
1 2 3 4 5 6 7 8 |
<filter> <filter-name>struts2</filter-name> <filter-class>Tools.Filter.StrutsPrepareAndExecuteFilterEx</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
经过上面的修改后,依旧是没办法进行网络访问的,原因是web.xml
中的Spring
拦截器并没有拦截WebSocket
的数据请求。
1 2 3 4 5 6 7 8 9 10 |
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> |
修改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/webSocketServer/*</url-pattern> </servlet-mapping> |
注意增加的
1 |
<async-supported>true</async-supported> |
下一步,配置Spring
的配置文件web
->WEB-INF
->dispatcher-servlet.xml
增加配置信息类的扫描目录包含我们刚刚创建的src
->Tools
->WebSocket
的目录(缺少这一步会导致我们通过注解实现的配置信息类没有被自动加载,导致无法访问),修改后的内容如下:
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Scan for spring annotated components --> <context:component-scan base-package="Tools.WebSocket"/> </beans> |
最后,调用的页面的代码
WebSocket.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>WebSocket</title> <style type="text/css"> #console-container { margin-left: 15px; margin-right: 15px; padding: 5px; width: 95%; } #console { border: 1px solid #CCCCCC; border-right-color: #999999; border-bottom-color: #999999; height: 300px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; } </style> <script type="text/javascript"> var url = 'ws://' + window.location.host + '/webSocketServer'; var ws = new WebSocket(url); ws.onopen = function () { log('Info: connection opened.'); }; ws.onmessage = function (event) { log('Received: ' + event.data); }; ws.onclose = function (event) { log('Info: connection closed.'); log(event); }; function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 1000) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; } </script> </head> <body> <div> <div id="console-container"> <div id="console"></div> </div> </div> </body> </html> |
最后的客户端显示效果如下图所示:
注意:如此创建的WebSocket
是会在两三分钟后主动断开连接的,原因在于WebSocket
需要周期性的发送心跳报文来维持连接。后续我们会尝试使用sockjs
来实现自动发送心跳的逻辑。
具体的sockjs的接入方法,参考IntelliJ IDEA 2016.2使用Spring 4.3.1.RELEASE,sockjs-1.1.1,stomp-1.2搭建基于Tomcat-7.0.68的WebSocket应用
IntelliJ IDEA2016.2使用Gradle创建Java Web应用
1.如下图,第一步很简单的,File
->New
->Project
2.如下图,完成第一步后,会弹出这样一个窗体,然后在左边栏目找到Gradle
,然后在右边勾选Java
和Web
两个选项,最后点击Next
。
3.如下图,到了输入GroupId
和AcrtifactId
窗口了,对于这两个名字的解释
ArtifactID就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
一般来说,包的命名习惯是域名的反过来,加个公司或者个人的名称吧,个人习惯。www.demo.com -> com.richard.demo; 那么都知道,test是项目名称,也是在最后面的,所有项目组的唯一标识符(groupId):com.richard, 项目的唯一标识符(ArtifactId)demo.
然后点击Next
。
4. 如下图,这个页面,刚进来默认选择的是Use default gradle wrapper(recommended)
, 我不选择这个是因为我本地有装Gradle
,所有不需要是用它默认的,如果选择它,那么创建项目之后,它就会去自动下载Gradle
,然后配置好,下载过 程一般都很慢,至少我在我电脑上很慢。所有我选择的是Use local gradle distribution
,。然后上面还有一个勾选,就是自动创建空的根目录文件夹,如果不选择,创建完的项目会没有Java
文件夹,所以勾选,让它自动创建吧,继续点击Next
。
5. 如下图,它默认的就是ArtifactId
的名字,项目的唯一标识嘛,然后module name
,如果不清楚应该填什么,可以按照默认的无所谓,点击Finish
,创建就这样完成了。
6.创建完成之后,如果你之前没有配置Tomcat
的话,是没办法运行的,所以也需要配置Tomcat
,如下图, 左侧是成功创建的项目文件目录,如果之前没有勾选Create directories for empty content roots automatically
, 那么就不会生成java
和resource
这个两个孔文件夹。这不的重点是点击Edit configuration
。
6. 弹出如下图配置框,点击左上角加号,往下滚动找到Tomcat Server
->Local
,点击Local
.
7. 如下图,弹出配置框,默认是配置Server
属性,输入这个配置的名字,name
,可以取任意的名字,点击Configure
选择本地Tomcat
的路径,都配置好了直接点击OK
就可以运行了。
8.如下图,然后选择Server
旁边的Deployment
, 页面之后,点击加号,在弹出的页面选择名字更长的那个,也就是后面有(exploded
)的那条,点击OK
。
9.如下图,在右侧输入Application context
的名字,这个对应就是等会儿运行时,默认路径(http://localhost:8080/demo/)中的demo, 所以如果你不配置这项,它的默认路径将会是(http://localhost:8080/)这样的。最后点击Apply
, 再点击OK
.
10.倒数第二步了,如下图,打开index.jsp
页面,长方形圈出来的是系统默认生成的,不用管,可以删掉,然后圆圈的是我自己写的。我只是为了让你知道,jsp页面长啥样子的,免得你看到它,以为是生成错文件了,点击有上角的运行按钮。
11.最后一步,见证如下成果。
参考链接
IntelliJ IDEA 2016.1.2建立Struts2+Spring+Hibernate+H2数据库项目
前言
参照IntelliJ IDEA 2016.1建立Strut2工程并使用Tomcat调试建立了项目后,然后按照IntelliJ IDEA 2016.1.1的Struts2项目中引入Junit4.12单元测试,引入Junit到项目之后,开始引入Hibernate
并且使用H2
作为数据存储,完成一个比较完整的示例服务器。
简单介绍一下H2
嵌入式数据库
H2
是一个短小精干的嵌入式数据库引擎,主要的特性包括:
- 免费、开源、快速;
- 嵌入式的数据库服务器,支持集群;
- 提供
JDBC
,ODBC
访问接口,提供基于浏览器的控制台管理程序; Java
编写,可使用GCJ
和IKVM.NET
编译;- 短小精干的软件,
1M
左右。
几个嵌入式数据库的对比:
实战
1.引入H2数据库
点击工程的"Project Structure
"图标,如下图所示:
在弹出的界面中根据顺序,依次选择,选择从Maven
服务器下载
在弹出的界面中根据顺序依次操作,点击搜索图标之后,要等待比较长的一段时间,才能看到下面的OK
按钮可以点击。目前H2
最新的版本是1.4.191
,因此输入"com.h2database:h2:1.4.191
"。详细操作如下图:
点击OK
按钮,关闭窗口后,稍等,会发现出现一个Problems
的提示,点击这个提示列表,如下图所示:
完成后点击OK
按钮关闭界面。
2.引入Hibernate框架
切换工程的视图到"Project
"模式下
项目上面右击鼠标,选择"Add Framework Support ...
"菜单,如下图:
在弹出的界面中选择"Hibernate
",如下图所示
点击后,出现下载进度,等待进度完成,如下图:
下载完成后,再次点击工程的"Project Structure
"图标,如下图:
同样在出现的界面中修复提示的Problems
,如下图:
增加"Hibernate
"配置文件,点击工程的"Project Structure
"图标,如下图:
增加"Hibernate
"配置文件,如下图:
选择文件的路径,此处我们使用默认路径,点击OK
即可。
此时我们点击工程目录,会发现,已经新增了一个名字为hibernate.cfg.xml
的配置文件,如下图:
3.配置Hibernate与H2数据库通信
按下面所示的修改hibernate.cfg.xml
文件,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 驱动位置 --> <property name="connection.driver_class">org.h2.Driver</property> <!-- 文件模式 db.h2文件--> <!-- <property name="connection.url">jdbc:h2:~/HibernateH2/db</property> --> <!-- 内存模式 --> <property name="connection.url">jdbc:h2:mem:db</property> <!-- 用户名 下面是密码 --> <property name="connection.username">sa</property> <property name="connection.password">sa</property> <!-- 使用的数据库方言 --> <property name="dialect">org.hibernate.dialect.H2Dialect</property> <property name="show_sql">true</property> <!-- DB schema will be updated if needed 自动创建表结构--> <property name="hbm2ddl.auto">update</property> <property name="current_session_context_class">thread</property> <!-- 引入的实体 --> <mapping class="Simulator.Hibernate.Model.Visitor"/> </session-factory> </hibernate-configuration> |
此时会提示我们,找不到Simulator.Hibernate.Model.Visitor
这个类,因此我们创建这个类,如下图所示:
三个文件的源代码如下:
Visitor.Java
中的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package Simulator.Hibernate.Model; import javax.persistence.*; import java.io.Serializable; @Entity @Table public class Visitor implements Serializable { @Id @GeneratedValue(strategy=GenerationType.TABLE,generator="tableGenerator") @TableGenerator(name="tableGenerator",initialValue=1,allocationSize=1) @Column(unique=true, nullable=false) public long id; /*消息记录的ID*/ public String v;/*版本号*/ public String TimeStamp; /*消息记录的时间戳*/ } |
代码解释一下,@Entry
,@Table
的注解来告知Hibernate
,这个是个数据库的表配置类,其中的每个成员变量对应数据库表的字段。
如下的注解
1 2 3 4 |
@Id @GeneratedValue(strategy=GenerationType.TABLE,generator="tableGenerator") @TableGenerator(name="tableGenerator",initialValue=1,allocationSize=1) @Column(unique=true, nullable=false) |
表示id
为整个表的自增主键。
VisitorDao.Java
中的代码如下,这个文件提供了访问数据的接口定义:
1 2 3 4 5 6 7 8 9 10 |
package Simulator.Hibernate.Dao; import Simulator.Hibernate.Model.Visitor; import java.util.List; public interface VisitorDao { boolean insert(Visitor visitor); List<Visitor> getAll(); } |
VisitorDaoImpl.Java
中的代码如下,这个文件对VisitorDao
中定义的接口进行了实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
package Simulator.Hibernate.Impl; import Simulator.Hibernate.Model.Visitor; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import java.util.ArrayList; import java.util.List; public class VisitorDaoImpl implements Simulator.Hibernate.Dao.VisitorDao{ @Override public boolean insert(Visitor visitor) { Configuration configuration = new Configuration(); configuration.configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry); try{ Session session = sessionFactory.openSession(); try { Transaction tas = session.beginTransaction(); try { session.save(visitor); tas.commit(); } catch (Exception ex) { ex.printStackTrace(); tas.rollback(); } }finally { session.close(); } }catch(Exception e){ e.printStackTrace(); return false; } return true; } @Override public List<Visitor> getAll(){ Configuration configuration = new Configuration(); configuration.configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry); try{ Session session = sessionFactory.openSession(); try { Transaction tas = session.beginTransaction(); try { Query query = session.createQuery("from Visitor"); tas.commit(); return query.list(); }catch (Exception e){ tas.rollback(); e.printStackTrace(); } }finally { session.close(); } }catch(Exception e){ e.printStackTrace(); } return new ArrayList<>(); } } |
这部分的代码需要着重解释一下
1 |
Query query = session.createQuery("from Visitor"); |
这个语句,注意,这个语句中的"from Visitor"
为Visitor.Java
中定义的类的名称,由Hibernate
内部进行变量,表之间的对应。
如上操作之后,就可以在任意的Action
中通过调用VisitorDaoImpl
实现对于数据库的写入,查询了。
参考链接
IntelliJ IDEA 2016.1.1的Struts2项目中引入Junit4.12单元测试
使用IntelliJ IDEA 2016.1建立Strut2工程并使用Tomcat调试建立项目后,想引入Junit进行TDD的开发,总结如下:
1.点击工程右上方的"Project Structure
"图标
2.在弹出的界面中的左侧选择"Libraries
",然后如下图所示,按照编号的顺序,依次点击,输入数据。注意,如果此时"OK
"按键是灰色的,那么需要点击右侧的放大镜图标,让IntelliJ IDEA
去服务器上搜索一下,等他搜索完成了,那么下面的"OK
"按键自然是可以点击的了。
3.点击"OK
"按键
4.此时发现提示存在一个"Problem
",点击然后按照下图展示修复这个问题。
点击"OK
",关闭这个页面。
5.在工程的"src
"目录下面新建名为"test
"的目录,他的子目录与源代码的目录相同即可,IntelliJ IDEA
会自动把这个目录当作单元测试的目录,如下图所示:
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import org.junit.Before; import org.junit.After; import org.junit.Test; public class testBasic { @Before public void before() throws Exception { } @Test public void myTest(){ } @After public void after() throws Exception { } } |
然后右击测试文件,会出现如下图的菜单选项
有时候他不会出现这些菜单,那说明还没有测试函数,添加一个空的@Test
测试函数就可以了,比如下面的样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import org.junit.Test; import org.junit.Before; import org.junit.After; /** * Basic Tester. * * @author <Authors name> * @since <pre>五月 10, 2016</pre> * @version 1.0 */ public class BasicTest { @Before public void before() throws Exception { } @Test public void myTest(){ } @After public void after() throws Exception { } } |
也可以使用JunitGenerator V2.0
这个插件来自动生成单元测试代码。
打开IntelliJ IDEA
工具,Alt+Ctrl+S
,弹出窗口如下:
在文本框中输入Plugins
进行插件搜索设置。
点击按钮,从插件资源库中安装新的插件。
从插件资源库中搜索JunitGenerator V2.0
版本,点击右侧的Install
按钮.
安装完成后,点击"Restart IntelliJ IDEA"重启IntelliJ IDEA。
现在可通过此工具自动完成test
类的生成了,在需要进行单元测试的类中Alt+Insert
生成的自动测试代码如下图所示
IntelliJ IDEA 2016.1建立Strut2工程并使用Tomcat调试
IntelliJ IDEA 2016.1
建立Strut2
工程的步骤如下:
1.从菜单中选择新建工程:
2.在弹出的窗口中,左侧的列表中,选择"Java
",在右侧的"Project SDK
"中指明需要的Java SDK
的版本,目前要求是1.8版本的,在下面的"Additional Libraries and Frameworks
"中找到"Struts 2
",并选中,同时选中"Web Application
"。
3.点击下面的"Next
"按钮。
4.等待IntelliJ IDEA
下载完成必须的插件。点击左侧的"Project
"边栏,之后可以到如下界面.
点击右侧的"Project Stucture
"按钮,如下图:
修复存在的问题:
点击后出现的界面如下:
在弹出的菜单中,选择"Put into /Web-INF/lib
"。
配置完成后的界面如下:
点击"OK
",关闭窗口。
5.编辑配置信息"Edit Configurations
"
6.在弹出的界面中点开右侧的"+"符号,也可以点击左侧顶部的"+"号。
7.在弹出的界面中,一直下拉,找到"Tomcat Server
",点击展开,选择"Local
"
8.下载并安装Tomcat 9
Windows下面,建议安装 "32-bit/64-bit Windows Service Installer
"
9.安装最新的 Java SE Development Kit
目前最新的版本是8u73
。保证电脑上面是最新的,如果使用JDK 7
的话,会由于Tomcat
的版本号太高导致在调试的时候报告如下错误:
1 2 |
Application Server was not connected before run configuration stop, reason: Unable to ping server at localhost:9099 |
这个错误的原因是由于JDK 1.7
是默认没有包含JMS
服务的,导致Idea
通过JMS
跟Tomcat
通信的时候失败。
10.设置Tomcat Server
配置完成后的界面显示如下:
此时底部提示"Warning No artificts configured
",点击底部的"Fix
"按钮。
出现的窗口中自动帮我们加入了"Tools:war exploded
"项目,点击下面的"Apply
"按钮后,点击"OK
"关闭设置页面。
11.调试,点击主界面上面的调试图标,即可进入调试,此时会在默认的浏览器上打开网页。
最后,浏览器上出现如下画面,说明设置成功。
12.创建一个简单的Stucts2
的MVC
例子----TimeConvert
(1)先创建一个Model
类来存放数据
首先,在src
目录上鼠标右击,选择"New
"-> "Java Class
"并在对话框中输入名字"Tools.Model.TimeConvertStore
",点击"OK
"。
里面的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package Tools.Model; public class TimeConvertStore { public String getConvertTime() { return convertTime; } public void setConvertTime(String time) { this.convertTime = time; } private String convertTime; } |
这个Model
类的public set
和get
方法允许访问private convertTime
字符串属性,Struts 2
框架需要将这个对象按照JavaBean
方式暴露给View(TimeConvert.jsp)
。
(2)创建View
页面来显示Model
类里存储的convertTime
.
在web
目录上鼠标右击,选择"New
"-> "File
"并在对话框中输入名字"TimeConvert.jsp
",点击"OK
"新建一个TimeConvert.jsp
的jsp
页面.
代码如下:
1 2 3 4 5 6 7 8 9 10 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Title</title> </head> <body> <h2><s:property value="timeConvertStore.convertTime" /></h2> </body> </html> |
页面中的taglib
告诉Servlet
容器这个页面将使用Struts 2
的tags
并且将它们用s
来表示。
s:property
的tag
标签返回调用TimeConvertAction controller class
的getTimeConvertStore
方法后的值。这个方法返回一个TimeConvertStore
对象。在TimeConvertStore
加上了.convertTime
后,就可以告诉Struts 2
框架将调用TimeConvertStore
的getConvertTime
方法。TimeConvertStore
的getConvertTime
方法返回一个字符串,然后这个字符串将被s:property
标签显示。
(3)创建一个Action
类TimeConvertAction.java
作为Controller
.
在src
目录上鼠标右击,选择"New
"->"Java Class
"并在对话框中输入名字"Tools.Controller.TimeConvertAction
",点击"OK
".
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package Tools.Controller; import Tools.Model.TimeConvertStore; import com.opensymphony.xwork2.ActionSupport; import java.text.SimpleDateFormat; import java.util.Date; public class TimeConvertAction extends ActionSupport { public String execute() throws Exception { timeConvertStore = new TimeConvertStore(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 timeConvertStore.setConvertTime(df.format(new Date())); return SUCCESS; } public TimeConvertStore getTimeConvertStore() { return timeConvertStore; } public void setTimeConvertStore(TimeConvertStore timeConvertStore) { this.timeConvertStore = timeConvertStore; } private TimeConvertStore timeConvertStore; private static final long serialVersionUID = 1L; } |
(4)增加struts
配置到struts.xml
文件中
建立映射关系,将TimeConvertAction
类(Controller
)和TimeConvert.jsp
(View)映射在一起。映射后,Struts 2
框架就能够知道哪个类将响应用户的action
(the URL
),这个类的哪个方法将被调用,哪个View
能够得到这个方法的返回String
结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="Tools" extends="struts-default"> <action name="TimeConvert" class="Tools.Controller.TimeConvertAction" method="execute"> <result name="success">/TimeConvert.jsp</result> </action> </package> </struts> |
(5)在index.jsp
中增加链接
首先在jsp
页面顶部增加taglib
说明
1 |
<%@ taglib prefix="s" uri="/struts-tags" %> |
然后在body
标签后增加p
标签
1 |
<p><a href="<s:url action='TimeConvert'/>">TimeConvert</a></p> |
修改后的代码如下:
1 2 3 4 5 6 7 8 9 10 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>$Title$</title> </head> <body> <p><a href="<s:url action='TimeConvert'/>">TimeConvert</a></p> </body> </html> |
点击调试后,运行效果如下图:
点击超链接后显示如下:
13.增加多语言支持i18n
需要注意的是,对于index.jsp
中读取全局配置文件,需要先增加Spring
框架,否则是无法通过在struts.xml
中增加
1 |
<constant name="struts.custom.i18n.resources" value="global" /> |
来实现的。如下图所示:
在跟"TimeConvertAction.java
"相同的目录下面建立英文语言文件TimeConvertAction_en.properties
,中文语言文件TimeConvertAction_zh.properties
,注意,中文只能是Unicode编码的格式,否则会出现乱码。格式类似\u65f6\u95f4\u8f6c\u6362
这样的格式。
其中TimeConvertAction_en.properties
中的内容如下:
1 |
Title=TimeConvert |
TimeConvertAction_cn.properties
中的内容如下:
1 |
Title=\u65f6\u95f4\u8f6c\u6362 |
然后修改TimeConvert.jsp
,在Title中引用我们定义的语言。修改
1 |
<title>Title</title> |
为:
1 |
<title><s:text name="Title"/></title> |
修改后的TimeConvert.jsp
文件如下:
1 2 3 4 5 6 7 8 9 10 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title><s:text name="Title"/></title> </head> <body> <h2><s:property value="TimeConvertStore.convertTime" /></h2> </body> </html> |
点击调试后,打开的页面中,会看到网页的Title变成了中文的"时间转换"。
14.Strut2
增加对Json
的支持
默认情况下Struts2
不支持直接返回JSON
,比较方便的方式是使用struts2-json-plugin
来支持。
(1)增加spring
框架,由于struts2-json-plugin
需要调用spring框架,因此需要增加spring框架。右击工程,选择"Add Framework Support...
"。
在弹出的窗口中,选择"Spring
","Spring MVC
"两项,同时在点击"Spring
"的时候,勾选"Create emtpy spring-config.xml
"。
然后点击"OK
",等待需要的Jar
包下载完成。成功下载完成后,可以在lib
目录下看到非常多的Jar
文件被添加进来了。在web
目录下的WEB-INF
目录下多出来了applicationContext.xml
,dispatcher-servlet.xml
这两个文件。
完成后点击界面上侧的"Project Structure
"图标,解决提示的Jar
包导出问题。
都选择第一项"Add 'xxxxxxxxxxx' to the artifact
".
(2)确认项目使用的Struts2
的版本。点击界面上侧的"Project Structure
"图标
从上图可以看到我们的Struts2
的版本是2.3.20.1
(3)手工去下载struts2-json-plugin插件,选择与我们的Struts2
的版本相同的版本的插件。之所以需要手工下载而不是要求IntelliJ IDEA
在Maven
中自动下载原因在于,由于我们建立项目的时候没有使用Maven
,因此我们项目Lib
目录下的Struts2
的Jar
包是没有带版本号的。而如果要求Maven
自动下载的话,会由于找不到带版本号的Struts2
的Jar
包,而自动引入一堆的带版本号的Struts2
的Jar
包。导致Struts2
的Jar
包出现两份,一份是有版本号的,一份是我们现在的样子。导致无法编译通过,因此还是手工引入即可。
由于我们的Struts2
的版本是2.3.20.1
,因此,我们下载2.3.20.1
版本的struts2-json-plugin
.
下载完成后放到项目的lib
目录下,然后右击struts2-json-plugin-2.3.20.1.jar
,选择"Add As Library
".
点击OK
后关闭。
继续点击界面右上侧的"Project Structure
"图标
修改src
目录下的struts.xml
。调整部分如下图所示。
action
的返回类型为json
时的可配置参数详解:
1 2 3 4 5 6 7 8 9 10 11 |
<result type="json"> <!-- 这里指定将被Struts2序列化的属性,该属性在action中必须有对应的getter方法 --> <!-- 默认将会序列所有有返回值的getter方法的值,而无论该方法是否有对应属性 --> <param name="root">dataMap</param> <!-- 指定是否序列化空的属性 --> <param name="excludeNullProperties">true</param> <!-- 这里指定将序列化dataMap中的那些属性 --> <param name="includeProperties">userList.*</param> <!-- 这里指定将要从dataMap中排除那些属性,这些排除的属性将不被序列化,一般不与上边的参数配置同时出现 --> <param name="excludeProperties">SUCCESS</param> </result> |
15.参考链接