??前面幾篇文章在帶Nvidia T4的GN7型虛擬主機(jī) Ubuntu18上安裝了Python 3.9的開發(fā)環(huán)境旦委,R-4.2.1的開發(fā)環(huán)境音诈,因?yàn)榇蠖鄶?shù)R軟件包都是C/C++編寫旬昭,升級(jí)了gcc/g++到11版(一些R軟件包要求C++14或17),編譯了一些小的C程序來測(cè)試OpenGL開發(fā)環(huán)境的安裝窘疮,并通過reticulate包在R中調(diào)用Python慌烧。Java的情況稍有不同鲫忍,互聯(lián)網(wǎng)世界的常用生產(chǎn)環(huán)境服務(wù)器端軟件主要是J2EE架構(gòu)的Java編寫膏燕,比如Weblogic、Tomcat悟民、阿里云煌寇、華為云等,所以在我的數(shù)據(jù)分析學(xué)習(xí)研究中逾雄,Java主要是作為J2EE服務(wù)器的運(yùn)行環(huán)境,而不是自己編碼的開發(fā)環(huán)境來配置腻脏,在本實(shí)驗(yàn)中鸦泳,要跑應(yīng)用層的Tomcat去集成中間層的Shiny Server,以及跑數(shù)據(jù)層的Neo4j來提供圖數(shù)據(jù)庫服務(wù)永品。然而R語言開發(fā)也可以通過rJava包直接調(diào)用Java程序做鹰,就像通過reticulate包調(diào)用Python程序一樣。Java程序的開發(fā)鼎姐,我一般在PC端用重量級(jí)的桌面IDE Eclipse或IntelliJ IDEA來完成钾麸,因?yàn)槟鞘窍喈?dāng)重量級(jí)的工作更振,像Rstudio Server、Jupyter Lab這類瀏覽器界面的輕量級(jí)Java IDE還沒有了解過饭尝。
??20年前開始學(xué)Java的時(shí)候肯腕,用的是WebSphere/WSAD,然后是Weblogic/Eclipse钥平,然后是Tomcat/Eclipse实撒,前幾年上云后又試用了IntelliJ IDEA。Java及J2EE規(guī)范這些年已經(jīng)有了很多變化涉瘾,JDK從1.2發(fā)展到了19知态,新東西了解的不多,不過積累的技能解決一些小問題還是夠用的立叛,比如為Neo4j開發(fā)了有向圖的朱劉算法最小樹形圖算法插件负敏。用Tomcat是因?yàn)橹攸c(diǎn)不在J2EE應(yīng)用層,演示性質(zhì)只需要作最小最簡(jiǎn)單的封裝集成秘蛇,簡(jiǎn)便為主其做,只需要輕量級(jí)的web容器即可。
??在多層應(yīng)用體系的集成中彤叉,J2EE容器中的Java程序庶柿,也可以直接調(diào)用R語言程序,本篇將用一個(gè)微博詞云的例子來演示一下秽浇。
1浮庐、安裝OpenJDK-11,Noe4j 4.X要求JDK 11柬焕。
root@VM-0-14-ubuntu:~# apt-get install openjdk-11-jdk
正在讀取軟件包列表... 完成
正在分析軟件包的依賴關(guān)系樹
正在讀取狀態(tài)信息... 完成
將會(huì)同時(shí)安裝下列軟件:
at-spi2-core ca-certificates-java fonts-dejavu-extra java-common libasound2 libasound2-data libatk-bridge2.0-0 libatk-wrapper-java libatk-wrapper-java-jni libatk1.0-0 libatk1.0-data
libatspi2.0-0 libpcsclite1 openjdk-11-jdk-headless openjdk-11-jre openjdk-11-jre-headless
建議安裝:
default-jre libasound2-plugins alsa-utils pcscd openjdk-11-demo openjdk-11-source visualvm libnss-mdns fonts-ipafont-gothic fonts-ipafont-mincho fonts-indic
下列【新】軟件包將被安裝:
at-spi2-core ca-certificates-java fonts-dejavu-extra java-common libasound2 libasound2-data libatk-bridge2.0-0 libatk-wrapper-java libatk-wrapper-java-jni libatk1.0-0 libatk1.0-data
libatspi2.0-0 libpcsclite1 openjdk-11-jdk openjdk-11-jdk-headless openjdk-11-jre openjdk-11-jre-headless
升級(jí)了 0 個(gè)軟件包审残,新安裝了 17 個(gè)軟件包,要卸載 0 個(gè)軟件包斑举,有 0 個(gè)軟件包未被升級(jí)搅轿。
需要下載 261 MB 的歸檔。
解壓縮后會(huì)消耗 413 MB 的額外空間富玷。
您希望繼續(xù)執(zhí)行嗎璧坟? [Y/n] y
root@VM-0-14-ubuntu:~# java --version
openjdk 11.0.17 2022-10-18
OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu218.04)
OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu218.04, mixed mode, sharing)
root@VM-0-14-ubuntu:~# which java
/usr/bin/java
root@VM-0-14-ubuntu:~# export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
root@VM-0-14-ubuntu:~# echo $JAVA_HOME
/usr/lib/jvm/java-11-openjdk-amd64
2、設(shè)置環(huán)境變量赎懦。
root@VM-0-14-ubuntu:~# vi /etc/profile
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export JRE_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$PATH:$JAVA_HOME/bin
3雀鹃、安裝Tomcat,啟動(dòng)一下驗(yàn)證安裝励两。
A黎茎、下載解壓安裝。
root@VM-0-14-ubuntu:~# wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.0.27/bin/apache-tomcat-10.0.27.tar.gz
root@VM-0-14-ubuntu:~# tar -xzvf apache-tomcat-10.0.27.tar.gz
root@VM-0-14-ubuntu:~# mv /home/ubuntu/apache-tomcat-10.0.27 /usr/local/apache-tomcat-10.0.27
root@VM-0-14-ubuntu:~# cd /usr/local/apache-tomcat-10.0.27/bin
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# export CATALINA_HOME=/usr/local/apache-tomcat-10.0.27
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# ./startup.sh &
B当悔、輸出環(huán)境變量:
root@VM-0-14-ubuntu:~# vi /etc/profile
# Added for Tomcat
export CATALINA_HOME=/usr/local/apache-tomcat-10.0.27
export CATALINA_BASE=/usr/local/apache-tomcat-10.0.27
C傅瞻、配置管理賬戶:
root@VM-0-14-ubuntu:~# cd /usr/local/apache-tomcat-10.0.27/conf
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/conf# vi tomcat-users.xml
<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="admin-gui"/>
<user username="admin" password="1234" roles="manager-gui"/>
??其中用戶名為tomcat踢代,密碼為tomcat的是用來登錄tomcat的Host Manager的,而用戶名為admin嗅骄,密碼為1234是用來登錄tomcat的App Manager的胳挎。
D、啟停管理:
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# ./startup.sh
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# ./shutdown.sh
E掸读、允許從遠(yuǎn)程登錄Tomcat App Manager與Host Manager:
??在這兩個(gè)Tomcat Web App的 ./META-INF/context.xml中找到下面限制訪問IP的一段注釋掉串远。
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/webapps/manager/META-INF# vi context.xml
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/webapps/host-manager/META-INF# vi context.xml
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
F、Tomcat10注意事項(xiàng)儿惫。
從Tomcat10開始澡罚,Java EE變成Jakarta EE,參閱Tomcat 10 主頁:
1)所有javax開頭的包都重命名為jakarta開頭肾请,后文中所有引用javax.servlet開頭的類都要轉(zhuǎn)換為jakarta.servlet開頭留搔。
2)JSP的java 規(guī)范更新為Dynamic Web Module 5.0,需要Eclipse 2021-03以后版本的支持铛铁,參閱資料1隔显,參閱資料2。已有Java Web項(xiàng)目更改project facet升級(jí)Dynamic Web Module規(guī)范可以參閱該帖子修改org.eclipse.wst.common.project.facet.core.xml饵逐。
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<runtime name="Apache Tomcat v10.0"/>
<fixed facet="java"/>
<fixed facet="jst.web"/>
<fixed facet="wst.jsdt.web"/>
<installed facet="jst.web" version="5.0"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="java" version="11"/>
</faceted-project>
如果不想修改源碼括眠,要用Tomcat 9以下的版本。
4倍权、為Tomcat配置SSL加密連接掷豺。
A、生成JKS格式的keystore薄声。使用的是與前面Nginx等相同的自簽數(shù)字證書與密鑰当船,先打包為P12格式,再由P12格式轉(zhuǎn)換為JKS格式默辨。數(shù)字證書也是把自簽CA的數(shù)字證書帶上德频,形成完整的證書鏈。
# cd /root/cert
# openssl pkcs12 -export -inkey server.key -in server.crt -chain -CAfile \
./demoCA/cacert.pem -out server.p12 -name 106.52.33.185 -passout pass:123456
# keytool -importkeystore -v -srckeystore server.p12 -srcstoretype \
pkcs12 -srcstorepass 123456 -destkeystore server.jks \
-deststoretype jks -deststorepass 123456
B缩幸、為Tomcat配置一個(gè)HTTPS加密連接器壹置。
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/conf# vi server.xml
??注釋掉原來8080端口的http Connector,增加8443端口的 https Connector表谊,使用剛才生成的JKS密鑰庫蒸绩。參閱資料。
<!--
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate
certificateKeystoreFile="/root/cert/server.jks"
certificateKeystorePassword="123456"
type="RSA"
/>
</SSLHostConfig>
</Connector>
C铃肯、重啟Tomcat,訪問https://106.52.33.185:8443/ 传蹈。
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# ./shutdown.sh
root@VM-0-14-ubuntu:/usr/local/apache-tomcat-10.0.27/bin# ./startup.sh
5押逼、安裝Neo4j-4.4.6-CHS步藕。
??Neo4j已經(jīng)發(fā)布了5.1版,這里還是用4.4.6挑格,因?yàn)樗龅睦佣际窃?.2.6上測(cè)試過咙冗,涉及到Graph Data Sicence Library庫版本更新等,有向圖最小樹形圖算法只在GDSL 2.0上測(cè)試過漂彤。GDSL升級(jí)的話雾消,要評(píng)估一下最小樹形圖算法插件是否要修改程序,這個(gè)工作就不小了挫望。
A立润、下載解壓。
# wget --no-check-certificate https://we-yun.com/doc/neo4j-chs/4.4.6/neo4j-chs-community-4.4.6-unix.tar.gz
# tar -xf neo4j-chs-community-4.4.6-unix.tar.gz
# mv neo4j-chs-community-4.4.6-unix /opt/neo4j-chs-community-4.4.6-unix
B媳板、啟動(dòng)一次桑腮,創(chuàng)建服務(wù)器的目錄結(jié)構(gòu)。
# cd /opt/neo4j-chs-community-4.4.6-unix/bin
# ./neo4j console
??該命令會(huì)創(chuàng)建服務(wù)器的目錄結(jié)構(gòu)蛉幸。
root@VM-0-14-ubuntu:/opt/neo4j-chs-community-4.4.6-unix/bin# ./neo4j console
Directories in use:
home: /opt/neo4j-chs-community-4.4.6-unix
config: /opt/neo4j-chs-community-4.4.6-unix/conf
logs: /opt/neo4j-chs-community-4.4.6-unix/logs
plugins: /opt/neo4j-chs-community-4.4.6-unix/plugins
import: /opt/neo4j-chs-community-4.4.6-unix/import
data: /opt/neo4j-chs-community-4.4.6-unix/data
certificates: /opt/neo4j-chs-community-4.4.6-unix/certificates
licenses: /opt/neo4j-chs-community-4.4.6-unix/licenses
run: /opt/neo4j-chs-community-4.4.6-unix/run
Starting Neo4j.
2022-11-15 03:20:27.633+0000 INFO Starting...
2022-11-15 03:20:28.048+0000 INFO This instance is ServerId{7a81ce5a} (7a81ce5a-e54a-47e2-9eec-628a84b3f33c)
2022-11-15 03:20:29.168+0000 INFO ======== Neo4j 4.4.6 ========
2022-11-15 03:20:35.443+0000 INFO Initializing system graph model for component 'security-users' with version -1 and status UNINITIALIZED
2022-11-15 03:20:35.449+0000 INFO Setting up initial user from defaults: neo4j
2022-11-15 03:20:35.449+0000 INFO Creating new user 'neo4j' (passwordChangeRequired=true, suspended=false)
2022-11-15 03:20:35.464+0000 INFO Setting version for 'security-users' to 3
2022-11-15 03:20:35.466+0000 INFO After initialization of system graph model component 'security-users' have version 3 and status CURRENT
2022-11-15 03:20:35.469+0000 INFO Performing postInitialization step for component 'security-users' with version 3 and status CURRENT
2022-11-15 03:20:36.679+0000 INFO Called db.clearQueryCaches(): Query cache already empty.
2022-11-15 03:20:36.776+0000 INFO Bolt enabled on localhost:7687.
2022-11-15 03:20:37.382+0000 INFO Remote interface available at http://localhost:7474/
2022-11-15 03:20:37.385+0000 INFO id: 37DBFB9339E01F74BE1F4295B1D871ECB678F865B7597DD67F58A120A61DABB7
2022-11-15 03:20:37.385+0000 INFO name: system
2022-11-15 03:20:37.385+0000 INFO creationDate: 2022-11-15T03:20:30.077Z
2022-11-15 03:20:37.385+0000 INFO Started.
^C2022-11-15 03:20:45.691+0000 INFO Neo4j Server shutdown initiated by request
2022-11-15 03:20:45.692+0000 INFO Stopping...
2022-11-15 03:20:50.944+0000 INFO Stopped.
C破讨、拷貝空白數(shù)據(jù)庫neo4j備份,社區(qū)版不支持多個(gè)并發(fā)數(shù)據(jù)庫奕纫,以后新建數(shù)據(jù)庫時(shí)拷貝該備份并重新命名提陶,然后切換至新的數(shù)據(jù)庫即可。
# cd /opt/neo4j-chs-community-4.4.6-unix/data/databases
# cp -R neo4j blank
D匹层、修改配置隙笆,打開網(wǎng)絡(luò)訪問地址等,默認(rèn)只偵聽loopback地址 127.0.0.1又固。這里把從CSV導(dǎo)入數(shù)據(jù)的許可目錄限制在/home/ubuntu/data仲器,Neo4j HTTPS仍然使用前面Shiny Server等服務(wù)器使用的同一個(gè)自簽服務(wù)器數(shù)字證書,不過bolt+s協(xié)議需要使用把服務(wù)器證書與自建CA證書拼接到一起包含完整鏈條的證書仰冠,否則Chrome瀏覽器不能連接bolt+s協(xié)議乏冀,具體可參閱:參考資料1,參考資料2洋只,參考資料3辆沦。
# cd /opt/neo4j-chs-community-4.2.6-unix/conf
# vi neo4j.conf
# 打開網(wǎng)絡(luò)訪問地址
dbms.default_listen_address=0.0.0.0
# 啟動(dòng)時(shí)打開的數(shù)據(jù)庫,社區(qū)版只能在線打開一個(gè)數(shù)據(jù)庫识虚,通過改變下面的名字切換肢扯。
# Change to the database you want
dbms.default_database=neo4j
# 切換時(shí)重建事務(wù)日志,否則不能啟動(dòng)担锤,因?yàn)閿?shù)據(jù)庫變了蔚晨,不匹配。
# Create a new transaction log when change to a new database
dbms.recovery.fail_on_missing_files=false
# 配置允許CSV數(shù)據(jù)文件導(dǎo)入,Linux上必須配置铭腕,
# 限制從其它目錄導(dǎo)入數(shù)據(jù)银择,以堵塞安全漏洞。
# This setting constrains all `LOAD CSV` import files to be under the `import` directory.
dbms.directories.import=/home/ubuntu/data
# Determines if Cypher will allow using file URLs when loading data using
# `LOAD CSV`. Setting this value to `false` will cause Neo4j to fail `LOAD CSV`
# clauses that load data from the file system.
dbms.security.allow_csv_import_from_file_urls=true
#取消對(duì)APOC及GDS過程的安全限制累舷。
# A comma separated list of procedures and user defined functions that are allowed
# full access to the database through unsupported/insecure internal APIs.
#dbms.security.procedures.unrestricted=my.extensions.example,my.procedures.*
dbms.security.procedures.unrestricted=jwt.security.*,gds.*,apoc.*
#打開用戶驗(yàn)證浩考,注釋掉后默認(rèn)是打開的。
# Whether requests to Neo4j are authenticated.
# To disable authentication, uncomment this line
#dbms.security.auth_enabled=false
# 網(wǎng)絡(luò)協(xié)議設(shè)置被盈,默認(rèn)在7474打開http析孽,7687打開bolt,
# 這里關(guān)閉http只怎,在默認(rèn)的7473打開https袜瞬,bolt打開SSL。
# Bolt connector
dbms.connector.bolt.enabled=true
dbms.connector.bolt.tls_level=REQUIRED
#dbms.connector.bolt.listen_address=:7687
#dbms.connector.bolt.advertised_address=:7687
# HTTP Connector. There can be zero or one HTTP connectors.
dbms.connector.http.enabled=false
# HTTPS Connector. There can be zero or one HTTPS connectors.
dbms.connector.https.enabled=true
#dbms.connector.https.listen_address=:7473
#dbms.connector.https.advertised_address=:7473
# Bolt SSL configuration
dbms.ssl.policy.bolt.enabled=true
dbms.ssl.policy.bolt.base_directory=/root/cert
dbms.ssl.policy.bolt.private_key=server.key
dbms.ssl.policy.bolt.public_certificate=server.crt
dbms.ssl.policy.bolt.client_auth=NONE
dbms.ssl.policy.https.enabled=true
dbms.ssl.policy.https.base_directory=/root/cert
dbms.ssl.policy.https.private_key=server.key
dbms.ssl.policy.https.public_certificate=server.crt
dbms.ssl.policy.https.client_auth=NONE
E尝盼、增加環(huán)境變量吞滞。
# vi /etc/profile
# Added for Neo4j
export NEO4J_HOME=/opt/neo4j-chs-community-4.4.6-unix
export NEO4J_CONF=$NEO4J_HOME/conf
F、重啟Neo4j盾沫,訪問https://106.52.33.185:7473測(cè)試裁赠。默認(rèn)用戶名/口令是 neo4j/neo4j,第一次登錄要改密碼赴精。
G佩捞、安裝APOC、GDSL等plug-in,拷貝到plugins目錄,注意要和Neo4j的版本匹配蕾哟,具體參閱APOC主頁與GDSL主頁一忱。下列的*-SNAPSHOT.jar是我開發(fā)的算法插件。
root@VM-0-14-ubuntu:/opt/neo4j-chs-community-4.4.6-unix# cd plugins
root@VM-0-14-ubuntu:/opt/neo4j-chs-community-4.4.6-unix/plugins# ls
apoc-4.4.0.1-all.jar neo4j-graph-data-science-2.0.2.jar open-gds-extend-0.0.1-SNAPSHOT.jar rs-4.0.0.jar
neo4j-functions-1.0.0-SNAPSHOT.jar ojdbc8-19.8.0.0.jar README.txt rs-license-4.0.0.Trial.00000000-0000-0000-0000-000000000000.20211231.txt
??重啟Neo4j谭确,測(cè)試GDSL及APOC的安裝帘营。
??測(cè)試最小樹形圖算法,在Neo4j Browser上逐條語句執(zhí)行逐哈。
// 清空?qǐng)D芬迄,刪除所有結(jié)點(diǎn)與關(guān)系
match(n) detach delete n;
// 創(chuàng)建測(cè)試圖
CREATE(a:Node {name: 'a'}),
(b:Node {name: 'b'}),
(c:Node {name: 'c'}),
(d:Node {name: 'd'}),
(e:Node {name: 'e'}),
(b)<-[:TYPE {cost:17}]-(a), (c)<-[:TYPE {cost:16}]-(a), (d)<-[:TYPE {cost:19}]-(a), (e)<-[:TYPE {cost:16}]-(a),
(c)<-[:TYPE {cost:3}]-(b), (d)<-[:TYPE {cost:3}]-(b), (e)<-[:TYPE {cost:11}]-(b),
(b)<-[:TYPE {cost:3}]-(c), (d)<-[:TYPE {cost:4}]-(c), (e)<-[:TYPE {cost:8}]-(c),
(b)<-[:TYPE {cost:3}]-(d), (c)<-[:TYPE {cost:4}]-(d), (e)<-[:TYPE {cost:12}]-(d),
(b)<-[:TYPE {cost:11}]-(e), (c)<-[:TYPE {cost:8}]-(e), (d)<-[:TYPE {cost:12}]-(e);
// 建立圖的投影graph
CALL gds.graph.project(
'graph',
'Node',
{
LINK: {
type: 'TYPE',
properties: 'cost',
orientation: 'NATURAL'
}
}
) ;
// 調(diào)用最小樹形圖算法
MATCH (n:Node {name: 'a'})
CALL gds.alpha.spanningArborescenceReverse.minimum.write('graph', {
startNodeId: id(n),
relationshipWeightProperty: 'cost',
writeProperty: 'MINSA',
weightWriteProperty: 'cost'
});
YIELD preProcessingMillis, computeMillis, writeMillis, effectiveNodeCount
RETURN preProcessingMillis, computeMillis, writeMillis, effectiveNodeCount;
//輸出最小樹形圖
MATCH path = (n:Node {name: 'a'})-[:MINSA*]-()
WITH relationships(path) AS rels
UNWIND rels AS rel
WITH DISTINCT rel AS rel
RETURN startNode(rel) as source, endNode(rel) AS destination, rel;
// 刪除圖的投影graph(如果有)
CALL gds.graph.drop( 'graph');
6、配置開機(jī)啟動(dòng)Tomcat與Neo4j
??這個(gè)鏡像已經(jīng)激活了rc.local服務(wù)昂秃,把啟動(dòng)命令加入/etc/rc.d/rc.local即可禀梳,重新輸出那些環(huán)境變量是因?yàn)殚_機(jī)自啟動(dòng)進(jìn)程沒有登錄的動(dòng)作,不會(huì)執(zhí)行/etc/profile等設(shè)置肠骆。
# vi /etc/rc.d/rc.local
# Added by Jean for java, 2022/11/12
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$PATH:$JAVA_HOME/bin
export JRE_HOME=$JAVA_HOME
export CLASS_PATH=$JAVA_HOME/lib:$CLASS_PATH
# Added for Tomcat
export CATALINA_HOME=/usr/local/apache-tomcat-10.0.27
export CATALINA_BASE=/usr/local/apache-tomcat-10.0.27
# Added for Neo4j
export NEO4J_HOME=/opt/neo4j-chs-community-4.4.6-unix
export NEO4J_CONF=$NEO4J_HOME/conf
# Added for rJava
export LD_LIBRARY_PATH=$JAVA_HOME/lib/server:$LD_LIBRARY_PATH
# Startup Tomcat
cd /usr/local/apache-tomcat-10.0.27/bin
./startup.sh
# Startup Neo4j
cd /opt/neo4j-chs-community-4.4.6-unix/bin
./neo4j start
??測(cè)試一下:
# reboot now
7算途、配置rJava,像reticulate包一樣蚀腿,通過rJava包嘴瓤,可以在R中直接調(diào)用java語言的程序。
A、更新R的Java配置廓脆。
root@VM-0-14-ubuntu:~# R CMD javareconf
Java interpreter : /usr/lib/jvm/java-11-openjdk-amd64/bin/java
Java version : 11.0.17
Java home path : /usr/lib/jvm/java-11-openjdk-amd64
Java compiler : /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
Java headers gen.:
Java archive tool: /usr/lib/jvm/java-11-openjdk-amd64/bin/jar
trying to compile and link a JNI program
detected JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
detected JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
gcc -I"/usr/lib64/R-4.2.1/lib/R/include" -DNDEBUG -I/usr/lib/jvm/java-11-openjdk-amd64/include -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux -I/usr/local/include -fpic -g -O2 -c conftest.c -o conftest.o
gcc -shared -L/usr/lib64/R-4.2.1/lib/R/lib -L/usr/local/lib -o conftest.so conftest.o -L/usr/lib/jvm/java-11-openjdk-amd64/lib/server -ljvm -L/usr/lib64/R-4.2.1/lib/R/lib -lR
JAVA_HOME : /usr/lib/jvm/java-11-openjdk-amd64
Java library path: $(JAVA_HOME)/lib/server
JNI cpp flags : -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
JNI linker flags : -L$(JAVA_HOME)/lib/server -ljvm
Updating Java configuration in /usr/lib64/R-4.2.1/lib/R
Done.
??參考該帖子畏浆。上面的命令會(huì)更新/usr/lib64/R-4.2.1/lib/R/etc/ldpaths,更新后要重啟機(jī)器才會(huì)生效狞贱。
B、安裝rJava包蜀涨。
> install.packages("rJava")
C瞎嬉、調(diào)用java對(duì)象及函數(shù)測(cè)試。參考資料1厚柳,參考資料2氧枣。
library(rJava)
.jinit()
s <- .jnew("java/lang/String", "Hello World!")
print(s)
.jcall(s,"I","length")
s$length()
J("java.lang.Double", "parseDouble", "10.2")
8、在Java中通過Rserve調(diào)用R别垮。
??Rserve通過標(biāo)準(zhǔn)的TCP/IP服務(wù)端口向外提供R語言的調(diào)用便监,因此為傳統(tǒng)的J2EE Web應(yīng)用等系統(tǒng)提供了大數(shù)據(jù)分析與作圖的能力,從而擴(kuò)充了這些系統(tǒng)碳想,可以有效的整合與盤活各種存量軟硬件與數(shù)據(jù)資產(chǎn)烧董,這個(gè)系統(tǒng)集成方案的性價(jià)比非常高,Tableau等數(shù)據(jù)科學(xué)公司也在用胧奔。
參考: R語言服務(wù)器程序 Rserve詳解逊移,配置用戶驗(yàn)證。
How to enable T.L.S 1.2 in R-Serve龙填,配置SSL胳泉。
Rserve TLS SSL Support, 選擇使用的協(xié)議與參數(shù)。
Configuration directives supported by latest Rserve version岩遗。
A扇商、安裝,參閱Rserve Github主頁:
> install.packages("Rserve")
B宿礁、配置:
root@VM-0-14-ubuntu:/home/ubuntu# vi /etc/Rserv.conf
??SSL連接使用與前面相同的自簽數(shù)字證書與密鑰案铺。
//允許遠(yuǎn)程登錄
remote enable
//連接需要用戶驗(yàn)證
auth required
//驗(yàn)證密碼不允許明文
plaintext disable
//使用utf-8編碼
encoding utf8
//允許遠(yuǎn)程控制后臺(tái)R進(jìn)程
control enable
//使用qap+tls協(xié)議
qap.tls.port 6311
//Rserve服務(wù)器密鑰
tls.key /root/cert/server.key
//Rserve服務(wù)器證書,這里是自簽證書
tls.cert /root/cert/server.crt
//可選窘拯,服務(wù)器CA證書
tls.ca /root/cert/demoCA/cacert.pem
//禁用非加密的qap協(xié)議
qap disable
C红且、配置開機(jī)自動(dòng)啟動(dòng)。
root@VM-0-14-ubuntu:/home/ubuntu# vi /etc/rc.d/rc.local
# Startup Rserve with /etc/Rserv.conf
cd /usr/lib64/R-4.2.1/bin
./R CMD Rserve --no-save
D涤姊、本機(jī)測(cè)試SSL連接暇番,可以與配好的Nginx SSL端口比較一下以確認(rèn)。
#openssl s_client -connect localhost:6311 -tls1_2
#openssl s_client -connect localhost:443 -tls1_2
root@VM-0-14-ubuntu:/usr/lib64/R-4.2.1/bin# openssl s_client -connect localhost:6311 -tls1_2
CONNECTED(00000003)
......
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: D42CB7A107EDBAAC42CF290542C5A68CC8B364BAB837CC414C68A600C6F758D4
Session-ID-ctx:
Master-Key: 3C0166A753FB4D68B0068B3D068C8963FF32BEE82FD15765D73FA390350A87AB259AC0F11F4462E7110B6DE1BEBC1563
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 7200 (seconds)
TLS session ticket:
......
Start Time: 1668394246
Timeout : 7200 (sec)
Verify return code: 19 (self signed certificate in certificate chain)
Extended master secret: yes
---
Rsrv0103QAP1
ARucK9E ------
E思喊、本機(jī)測(cè)試R客戶端連接壁酬,先用localhost再用外網(wǎng)IP測(cè)試。
# R
> install.packages(“RSclient”)
> library(RSclient)
> conn<-RS.connect(host="127.0.0.1",tls=TRUE, verify=FALSE)
INFO: peer nas NO cert
> RS.login(conn,"ubuntu","password",authkey=RS.authkey(conn))
[1] TRUE
> RS.eval(conn,rnorm(5))
[1] 1.047752e+00 2.513512e+00 -7.279324e-01 -6.308483e-05 1.698458e-01
> conn<-RS.connect(host="106.52.33.185",tls=TRUE, verify=FALSE)
INFO: peer nas NO cert
> RS.login(conn,"ubuntu","password",authkey=RS.authkey(conn))
[1] TRUE
> RS.eval(conn,rnorm(5))
[1] -0.1932565 -1.7393902 1.7531404 0.1870313 1.7429810
>
F、客戶端Rstudio測(cè)試R客戶端連接舆乔,同上岳服。
G、增加一個(gè)專用Linux系統(tǒng)用戶以用于遠(yuǎn)程訪問Rserve希俩,以增加安全性吊宋。
#adduser rserve
#passwd rserve
H、在Java中調(diào)用Rserve颜武。
??現(xiàn)在可以先看看部署在另一個(gè)普通虛擬主機(jī)上的例子璃搜,Tomcat Web App中Java調(diào)用R語言生成微博詞云圖。因?yàn)槲⒉┑尿?yàn)證機(jī)制鳞上,本地存儲(chǔ)的微博驗(yàn)證令牌會(huì)有一段時(shí)間的有效期这吻,有效期過后就不能正確連接微博讀取數(shù)據(jù),這時(shí)詞云輸出的就是空白篙议,需要在Rstudio中運(yùn)行程序重新驗(yàn)證獲得有效的令牌唾糯。
??在Java客戶端里,主要是通過Rengin包連接Rserve鬼贱,然后需要注意的是移怯,因?yàn)镽serve配置了SSL,需要把服務(wù)器自簽數(shù)字證書的CA根證書加入到JDK的受信任根證書列表中吩愧,開發(fā)環(huán)境是PC端的JDK芋酌,部署運(yùn)行環(huán)境是服務(wù)器端的JDK。JDK8與JDK11已經(jīng)沒有jre目錄雁佳,為保持兼容可以自己生成脐帝,反正找到JDK的lib/security目錄,cacerts文件在該目錄下糖权,Windows上也是一樣的堵腹。執(zhí)行下面的命令導(dǎo)入根證書:
root@VM-0-14-ubuntu:/usr/lib/jvm/java-11-openjdk-amd64/lib/security# ls
blacklisted.certs blocked.certs cacerts default.policy public_suffix_list.dat
root@VM-0-14-ubuntu:/usr/lib/jvm/java-11-openjdk-amd64/lib/security# keytool -import -alias Jean -file /root/cert/demoCA/cacert.pem -keystore cacerts -storepass changeit
警告: 使用 -cacerts 選項(xiàng)訪問 cacerts 密鑰庫
所有者: CN=RootCA, OU=Study, O=Jean, L=ZhuHai, ST=GD, C=CN
發(fā)布者: CN=RootCA, OU=Study, O=Jean, L=ZhuHai, ST=GD, C=CN
序列號(hào): 40c0c7317eacfdaf07c9e692bded553d0806bce1
生效時(shí)間: Wed Nov 02 17:40:39 CST 2022, 失效時(shí)間: Sat Oct 30 17:40:39 CST 2032
證書指紋:
SHA1: EB:40:C8:EC:BA:D1:6B:21:CD:CA:89:CE:1B:54:42:C6:9F:FB:89:36
SHA256: CD:DE:44:9D:7F:3B:D8:D1:6A:0E:69:E3:AB:F7:89:3E:E5:C7:28:C0:6E:E2:7E:8F:DC:0F:44:C6:85:EE:CF:A3
簽名算法名稱: SHA256withRSA
主體公共密鑰算法: 2048 位 RSA 密鑰
版本: 3
......
是否信任此證書? [否]: y
證書已添加到密鑰庫中
root@VM-0-14-ubuntu:/usr/lib/jvm/java-11-openjdk-amd64/lib/security# keytool -list -keystore cacerts -storepass changeit
警告: 使用 -cacerts 選項(xiàng)訪問 cacerts 密鑰庫
密鑰庫類型: JKS
密鑰庫提供方: SUN
您的密鑰庫包含 128 個(gè)條目
debian:ac_raiz_fnmt-rcm.pem, 2022年11月12日, trustedCertEntry,
證書指紋 (SHA-256): EB:C5:57:0C:29:01:8C:4D:67:B1:AA:12:7B:AF:12:F7:03:B4:61:1E:BC:17:B7:DA:B5:57:38:94:17:9B:93:FA
......
jean, 2022年11月14日, trustedCertEntry,
證書指紋 (SHA-256): CD:DE:44:9D:7F:3B:D8:D1:6A:0E:69:E3:AB:F7:89:3E:E5:C7:28:C0:6E:E2:7E:8F:DC:0F:44:C6:85:EE:CF:A3
??以后再用Eclipse建立一個(gè)Tomcat Web App項(xiàng)目來演示,通過Rserve調(diào)用R語言函數(shù)星澳,傳入?yún)?shù)疚顷,由rmarkdown根據(jù)參數(shù)生成一份PDF數(shù)據(jù)分析報(bào)告,然后在Web App結(jié)果頁面中顯示下載鏈接供下載閱讀禁偎。具體的Java項(xiàng)目與程序腿堤,篇幅也不小,大概需要另起一篇文章如暖,編寫也要一些時(shí)間笆檀,這里先介紹一下詞云例子的要點(diǎn)。
1)先在Rstudio中寫一個(gè)生成詞云圖的函數(shù)CiYunTongJi():
??這個(gè)函數(shù)接收一個(gè)參數(shù)盒至,少于最低詞頻的詞就不畫進(jìn)詞云圖募谎。函數(shù)中調(diào)用wordcloud2包生成詞云圖,這是個(gè)運(yùn)行在瀏覽器中的交互式網(wǎng)頁耳鸯,因?yàn)樵诜?wù)器端后臺(tái)沒有顯示窗口,要調(diào)用htmlwidgets包暫存網(wǎng)頁到磁盤棋嘲,然后調(diào)用webshot包截取網(wǎng)頁快照,就得到詞云圖矩桂。其余的代碼是連接微博抓取一些當(dāng)天的數(shù)據(jù)沸移,清理并分詞,整理成data frame order2侄榴。R源碼加載時(shí)會(huì)先執(zhí)行非函數(shù)部分的代碼阔籽,然后Java端調(diào)用CiYunTongJi()函數(shù)時(shí),直接在order2上過濾詞條牲蜀。詞云圖以臨時(shí)文件存儲(chǔ)路徑的方式返回,在結(jié)果展示頁面中绅这,發(fā)送詞云圖后就把臨時(shí)文件刪除涣达。
library(openxlsx)
library(Rweibo)
library(jiebaR)
library(tm)
library(wordcloud2)
library(webshot)
library(htmlwidgets)
freq<-15
CiYunTongJi<- function(freq1){
cp<-tryCatch({
as.integer(freq1)
}, error = function(e) {
15
})
if (cp<=0)
cp<-15;
order3<-order2[which(order2$freq>= cp),]
#寫入到磁盤
fn<<-paste(getwd(),"/WeiBoCiYun",as.character(as.numeric(Sys.time())),".png",sep="")
tempfn = paste(getwd(),"/WeiBoCiYun",as.character(as.numeric(Sys.time())),".html",sep="")
ciyun<-wordcloud2(order3,size = 1,minRotation = -pi/3, maxRotation = pi/3,rotateRatio = 0.8,
fontFamily = "微軟雅黑", color = "random-light", shape = 'star')
# 暫存網(wǎng)頁
saveWidget(ciyun,tempfn , selfcontained = F)
# 網(wǎng)頁截圖
webshot(tempfn, fn, delay = 0.5, vwidth = 800, vheight = 800)
results <<- list(f1 = fn)
return(results)
}
#微博轉(zhuǎn)換為數(shù)據(jù)框
weibo2dataframe<-function(res){
#i<-1
dt<- data.frame(uid= character(), name= character(),screen_name= character(),
id= character(),text= character(), created_at= character())
for(i in 1:length(res)){
tmp<- data.frame(uid= res[[i]]$user$idstr, name= res[[i]]$user$name,screen_name= res[[i]]$user$screen_name,
id= res[[i]]$idstr,text= res[[i]]$text, created_at= res[[i]]$created_at)
dt<-rbind(dt,tmp)
}
return (dt)
}
roauth <- createOAuth("RJean", "rweibo")
#爬蟲循環(huán)爬取一些微博,轉(zhuǎn)成數(shù)據(jù)框证薇,做文本挖掘測(cè)試
wdt<- data.frame(uid= character(), name= character(),screen_name= character(),
id= character(),text= character(), created_at= character())
for(i in 1:10){
res<- statuses.friends_timeline(roauth,page=i, count = 100)
if(length(res)>0){
tmp<-weibo2dataframe(res)
wdt<-rbind(wdt,tmp)
cat(length(res))
cat("\n")
}else{cat(i); cat("\n");break}
}
#只看中央媒體的主題,要先加關(guān)注
#wdt2<-wdt[which(wdt$name %in% c("央視新聞","人民日?qǐng)?bào)","人民網(wǎng)","新浪新聞","新華網(wǎng)","頭條新聞","中國新聞網(wǎng)","環(huán)球時(shí)報(bào)","新浪博客","廣東稅務(wù)","珠海稅務(wù)")),]
wdt2<-wdt
#把微博文本向量轉(zhuǎn)換為語料庫
ovid <- Corpus(VectorSource(wdt2$text))
# 之后要對(duì)每一條微博進(jìn)行處理度苔,正則匹配去掉@,去掉標(biāo)點(diǎn)浑度,去掉里面出現(xiàn)的圖片等
s1 <- gsub('[a-zA-Z0-9]','',ovid)
s1 <- gsub('[\\pP+~$`^=|<>~`$^+=|<>¥×]','',s1)
s1 <- gsub('①|(zhì)②|③|④|⑤|⑥|⑦|⑧|⑨|℃|↓|→|丨','',s1)
#去掉各種副詞
s1<-gsub("[的|和|了|來|與|到|由|等|從|以|一|為|在|上|各|去|對(duì)|側(cè)|多|并|千|萬|年|更|向|這是]","",s1)
#分詞
seg<-worker()
seg<=s1
#建立詞頻
freq2<-freq(segment(s1,seg))
#按詞頻排序
index <- order(-freq2[,2])
order2<<-freq2[index, ]
# 調(diào)用測(cè)試一下
# CiYunTongJi("20")
2)在Java中調(diào)用CiYunTongJi()函數(shù)寇窑。
??定義一個(gè)輸入?yún)?shù)的頁面,它調(diào)用ServerLet /testR/CiYunRserve箩张。
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<!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=GBK">
<title>Insert title here</title>
</head>
<body>
<center>
<form action="/testR/CiYunRserve" method="get">
返回微博詞條的最小詞頻<br/>
詞頻閥值:<input type="number" name="freq" value=20><br/>
<input type="submit" value="開始統(tǒng)計(jì)">
</form>
</center>
</body>
</html>
??定義一個(gè)ServLet CiYunRserve.java來處理對(duì)R函數(shù)的調(diào)用甩骏。具體的處理中通過一個(gè)Helper類先初始化一個(gè)到Rserve的連接,然后執(zhí)行rc.voidEval("source(fn)")加載源碼CiYunTongJi.R先慷,rc.eval("freq<-'"+freq+"'")傳入?yún)?shù)饮笛,執(zhí)行x = (REXP)rc.eval("CiYunTongJi(freq)")調(diào)用R函數(shù)得到返回的結(jié)果列表,關(guān)閉Rserve連接论熙,把結(jié)果放入session對(duì)象中福青,跳轉(zhuǎn)到結(jié)果處理頁面,該頁面會(huì)從中提取結(jié)果脓诡,發(fā)送圖片并刪除臨時(shí)文件无午。這些接口函數(shù)都是Rsession包對(duì)Rengin包的進(jìn)一步封裝,用起來比較方便祝谚,具體見Rsession包主頁宪迟。
package test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.math.R.Rsession;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.RList;
/**
* Servlet implementation class CiYunRserve
*/
//@WebServlet("/CiYunRserve")
public class CiYunRserve extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public CiYunRserve() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
callRServe(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
public void callRServe(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
// if (session.getAttribute("rs") == null)
try {
String freq=request.getParameter("freq");
long t1 = System.currentTimeMillis();
Rsession rc =RServeHelper.getRsessionInstance();
String source = RServeHelper.prefix+"CiYunTongJi.R";
System.out.println(source);
rc.set("fn",source);
//rc.eval("source(fn)"裝入源程序總是出錯(cuò),用rc.voidEval("source(fn)")則可以
rc.voidEval("source(fn)");
rc.eval("freq<-'"+freq+"'");
REXP x ;
RList excels=null;
try{
x = (REXP)rc.eval("CiYunTongJi(freq)");
excels = x.asList();
} catch(Exception e){
e.printStackTrace();
}
// parse the result returned
for (int i = 0; i < excels.size(); i++) {
String gf = excels.at(i).asString();
System.out.println(gf);
}
long t2 = System.currentTimeMillis();
long t= (t2 - t1) / 1000 ;
System.out.println("耗時(shí):" +t+ "秒");
RServeHelper.endRsession(rc);
session.setAttribute("rs", excels);
session.setAttribute("time", t);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("顯示結(jié)果");
response.sendRedirect("./cy/rcjg.jsp");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
??結(jié)果處理頁面中實(shí)際發(fā)送詞云圖片由另一個(gè)發(fā)送圖片的ServLet執(zhí)行踊跟,頁面中只需給出它的超鏈接URL踩验,該ServLet發(fā)送圖片后可以刪除臨時(shí)文件鸥诽。
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<%@ page import="org.rosuda.REngine.RList,java.util.List"%>
<!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=GBK">
<title>詞云圖</title>
</head>
<body>
<center>
詞云圖<br/>
<%
if (session.getAttribute("rs")!=null){
//RList rs=(RList)session.getAttribute("rs");
RList rs=(RList)session.getAttribute("rs");
for (int i = 0; i < rs.size(); i++) {
String gf = rs.at(i).asString();
System.out.println(gf);
}
%>
<center><img src="/testR/ServePic?keep=true&filename=<%=rs.at("f1").asString()%>"></center>
<br/>
<center>耗時(shí): <%=session.getAttribute("time") %> 秒</center>
<%} %>
</center>
</body>
</html>
??這個(gè)Rserve連接幫助類主要是處理一下Windows開發(fā)環(huán)境與Linux部署環(huán)境的目錄差異。
package test;
import java.io.IOException;
import java.util.Properties;
import org.math.R.RserveSession;
import org.math.R.RserverConf;
import org.math.R.Rsession;
public class RServeHelper {
// private static boolean isWindows = false;
private static Rsession rsession = null;
private static String host = "124.223.110.20";
//public static String host="127.0.0.1";
public static String prefix = "../../../../home/jean/R/";
//public static String prefix="C:/Users/lenovo/Documents/Rscripts/";
public static String rpics = "/tmp/Rpics";
//public static String rpics="C:/Users/lenovo/Documents/Rpics";
/**
* 利用Rsession初始化RServe
*
* @return
* @throws IOException
*/
public static Rsession initRserve() throws IOException {
// 從配置文件中讀取Rserve信息箕憾,IP.用戶名.密碼
// Properties prop = PropertieHelper.getPropInstance("ssh.properties");
// String hostname = prop.getProperty("host");
// String username = prop.getProperty("username");
// String password = prop.getProperty("password");
// RserverConf rconf=new RserverConf(host,6311,username,password,new
// Properties());
Properties prop = new Properties();
prop.setProperty("tls", "true");
RserverConf rconf = new RserverConf(host, 6311, "rserve", "rserve@2022", prop);
rsession = RserveSession.newInstanceTry(System.out, rconf);
return rsession;
}
/**
* 創(chuàng)建Rsession單例
*
* @return
* @throws IOException
*/
public static Rsession getRsessionInstance() throws IOException {
if (rsession == null) {
rsession = initRserve();
}
return rsession;
}
public static void endRsession(Rsession rs) {
rs.end();
rsession = null;
}
}
??發(fā)送圖片的ServLet牡借,從Rserve讀取圖片,可以按需要?jiǎng)h除臨時(shí)文件袭异。
package test;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.math.R.Rsession;
/**
* Servlet implementation class ServePic
*/
@WebServlet("/ServePic")
public class ServePic extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ServePic() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String JPG = "image/png;charset=GB2312";
String gf = request.getParameter("filename");
String keep = request.getParameter("keep");
OutputStream out = response.getOutputStream();// 得到輸出流
response.setContentType(JPG);// 設(shè)定輸出的類型
callRServe(gf, out, keep);
out.close();
out.flush();
}
public void callRServe(String fn, OutputStream out, String keep) throws IOException {
Rsession rc =RServeHelper.getRsessionInstance();
try {
System.out.println(fn);
rc.getFile(out, fn);
if(keep==null||!keep.equalsIgnoreCase("true"))
rc.eval("unlink(fn); r");
RServeHelper.endRsession(rc);
} catch (Exception e) {
e.printStackTrace();
try{
RServeHelper.endRsession(rc);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
9钠龙、在Tomcat中部署Web App。
??在Eclipse中開發(fā)測(cè)試好Tomcat Web App后御铃,就可以打包輸出成war文件碴里,遠(yuǎn)程上傳部署到服務(wù)器上,然后在瀏覽器中訪問測(cè)試上真,這個(gè)比較簡(jiǎn)單咬腋,就不多說了。