Ubuntu18 Java語言環(huán)境安裝配置

??前面幾篇文章在帶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
為Tomcat配置HTTPS加密鏈接

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,第一次登錄要改密碼赴精。

Rstudio-installation-15.png

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的安裝帘营。


驗(yàn)證GDSL安裝

驗(yàn)證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');
測(cè)試有向圖最小樹形圖算法

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")

Rstudio中調(diào)用java

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)證獲得有效的令牌唾糯。

Tomcat Web App的JSP傳入?yún)?shù)調(diào)用R語言函數(shù)

R語言函數(shù)返回當(dāng)天微博的詞云圖

??在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)單咬腋,就不多說了。


Tomcat Web App Manager
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睡互,一起剝皮案震驚了整個(gè)濱河市根竿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌就珠,老刑警劉巖寇壳,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妻怎,居然都是意外死亡壳炎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門逼侦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匿辩,“玉大人,你說我怎么就攤上這事榛丢∪龊海” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵涕滋,是天一觀的道長(zhǎng)睬辐。 經(jīng)常有香客問我,道長(zhǎng)宾肺,這世上最難降的妖魔是什么溯饵? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮锨用,結(jié)果婚禮上丰刊,老公的妹妹穿的比我還像新娘。我一直安慰自己增拥,他們只是感情好啄巧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布寻歧。 她就那樣靜靜地躺著,像睡著了一般秩仆。 火紅的嫁衣襯著肌膚如雪码泛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天澄耍,我揣著相機(jī)與錄音噪珊,去河邊找鬼。 笑死齐莲,一個(gè)胖子當(dāng)著我的面吹牛痢站,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播选酗,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阵难,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了芒填?” 一聲冷哼從身側(cè)響起多望,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氢烘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體家厌,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡播玖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饭于。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜀踏。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖掰吕,靈堂內(nèi)的尸體忽然破棺而出果覆,到底是詐尸還是另有隱情,我是刑警寧澤殖熟,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布局待,位于F島的核電站,受9級(jí)特大地震影響菱属,放射性物質(zhì)發(fā)生泄漏钳榨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一纽门、第九天 我趴在偏房一處隱蔽的房頂上張望薛耻。 院中可真熱鬧,春花似錦赏陵、人聲如沸饼齿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缕溉。三九已至考传,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間倒淫,已是汗流浹背伙菊。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敌土,地道東北人镜硕。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像返干,于是被迫代替她去往敵國和親兴枯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容