Ver código fonte

添加cmove功能,添加http请求访问功能,添加数据库连接,添加xml解析

刘韬 5 anos atrás
pai
commit
cec521c4f8

+ 11 - 1
ZSKK_DicomServer/pom.xml

@@ -62,9 +62,19 @@
 			<artifactId>dcm4che-net</artifactId>
 			<version>5.18.0</version>
 		</dependency>
+		<dependency>
+			<groupId>org.dcm4che.tool</groupId>
+			<artifactId>dcm4che-tool-common</artifactId>
+			<version>5.18.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.squareup.okhttp3</groupId>
+			<artifactId>okhttp</artifactId>
+			<version>4.1.1</version>
+		</dependency>
 	</dependencies>
 	<build>
-		<finalName>zskk_dicomserver_v3.0Beta1</finalName>
+		<finalName>zskk_dicomserver_v3.0</finalName>
 		<plugins>
 			<plugin>
 				<artifactId>maven-war-plugin</artifactId>

+ 26 - 8
ZSKK_DicomServer/src/main/java/com/zskk/common/ZskkConfig.java

@@ -14,8 +14,12 @@ import com.jfinal.config.Plugins;
 import com.jfinal.config.Routes;
 import com.jfinal.core.JFinal;
 import com.jfinal.kit.PropKit;
+import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
+import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
+import com.jfinal.plugin.druid.DruidPlugin;
 import com.jfinal.template.Engine;
 import com.zskk.controller.DicomController;
+import com.zskk.model._MappingKit;
 import com.zskk.service.ServiceFactory;
 
 public class ZskkConfig extends JFinalConfig {
@@ -43,23 +47,37 @@ public class ZskkConfig extends JFinalConfig {
 	}
 
 	public void configRoute(Routes me) {
-		me.add("/msg", DicomController.class);
+		me.add("/dcm", DicomController.class);
+	}
+
+	public static DruidPlugin createZskkDruidPlugin() {
+
+		return new DruidPlugin(PropKit.get("jdbcUrl_zskk"), PropKit.get("user_zskk"),
+				PropKit.get("password_zskk").trim());
 	}
 
 	public void configPlugin(Plugins me) {
-		//预留数据库功能
+		// 配置数据库连接池插件
+		DruidPlugin druidPluginZskk = createZskkDruidPlugin();
+		me.add(druidPluginZskk);
+		// 配置ActiveRecord插件
+		ActiveRecordPlugin arpZskk = new ActiveRecordPlugin(druidPluginZskk);
+		arpZskk.setDialect(new MysqlDialect());
+    	//所有映射在 MappingKit 中自动化搞定
+		_MappingKit.mapping(arpZskk);
+		me.add(arpZskk);
 	}
 
 	public void configInterceptor(Interceptors me) {
-	
+
 	}
 
 	public void configHandler(Handlers me) {
 
 	}
 
-	/*/
-	 * 运行即启动
+	/*
+	 * / 运行即启动
 	 */
 	@Override
 	public void onStart() {
@@ -68,11 +86,11 @@ public class ZskkConfig extends JFinalConfig {
 		ServiceFactory.init();
 	}
 
-	/*/
-	 * 本地调试运行此处,线上发布注释main方法,并在maven配置文件注释jetty依赖
+	/*
+	 * / 本地调试运行此处,线上发布注释main方法,并在maven配置文件注释jetty依赖
 	 */
 	public static void main(String[] args) {
-		JFinal.start("src/main/webapp", 10000, "/", 5);
+		JFinal.start("src/main/webapp", 10001, "/", 5);
 	}
 
 	@Override

+ 31 - 1
ZSKK_DicomServer/src/main/java/com/zskk/controller/DicomController.java

@@ -1,8 +1,12 @@
 package com.zskk.controller;
 
 import com.jfinal.core.Controller;
+import com.zskk.controller.bean.ResultBean;
+import com.zskk.service.DicomCMoveService;
 import com.zskk.service.DicomEchoService;
+import com.zskk.service.InfoService;
 import com.zskk.service.ServiceFactory;
+import com.zskk.util.ErrorConstant;
 
 public class DicomController extends Controller {
 	
@@ -21,7 +25,33 @@ public class DicomController extends Controller {
 		} catch (Exception e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
-			renderText("DICOM Echo faild...");
+			renderText("DICOM Echo faild for reason:" + e.toString());
+		}
+	}
+	
+	public void cMove() {
+        String studyuid = getPara("studyuid");
+
+        DicomCMoveService dService =  new DicomCMoveService();
+        
+		try {
+			String resultString = dService.doMove(studyuid);;
+			renderText("result:" + resultString);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			renderText("DICOM CMove faild...");
+		}
+	}
+	
+	public void getOrderInfo() {
+        String applyNo = getPara("applyNo");
+		InfoService iService = ServiceFactory.getService(InfoService.class);
+		String resultString =  iService.getOrderInfo(applyNo);
+		if (resultString == null) {
+			renderJson(ErrorConstant.ERROR_NOT_FOUND);
+		}else {
+			renderJson(new ResultBean(resultString));
 		}
 	}
 	

+ 36 - 0
ZSKK_DicomServer/src/main/java/com/zskk/controller/bean/ResultBean.java

@@ -0,0 +1,36 @@
+package com.zskk.controller.bean;
+
+public class ResultBean {
+	private int code = 0;
+	private String msg;
+	private Object obj;
+	
+	public ResultBean(Object obj){
+		this.obj = obj;
+	}
+	
+	public ResultBean(int code, String msg){
+		this.code = code;
+		this.msg = msg;
+	}
+	
+	public int getCode() {
+		return code;
+	}
+	public void setCode(int code) {
+		this.code = code;
+	}
+	public String getMsg() {
+		return msg;
+	}
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+	public Object getObj() {
+		return obj;
+	}
+	public void setObj(Object obj) {
+		this.obj = obj;
+	}
+	
+}

+ 11 - 0
ZSKK_DicomServer/src/main/java/com/zskk/model/ApplynoStudyuid.java

@@ -0,0 +1,11 @@
+package com.zskk.model;
+
+import com.zskk.model.base.BaseApplynoStudyuid;
+
+/**
+ * Generated by JFinal.
+ */
+@SuppressWarnings("serial")
+public class ApplynoStudyuid extends BaseApplynoStudyuid<ApplynoStudyuid> {
+	public static final ApplynoStudyuid dao = new ApplynoStudyuid().dao();
+}

+ 15 - 0
ZSKK_DicomServer/src/main/java/com/zskk/model/_DataDictionary.txt

@@ -0,0 +1,15 @@
+Table: applyno_studyuid
+------------------+--------------+------+-----+---------+---------
+ Field            | Type         | Null | Key | Default | Remarks 
+------------------+--------------+------+-----+---------+---------
+ id               | INT(10)      | NO   | PRI |         | id      
+ ApplyNo          | VARCHAR(128) | NO   |     |         | 申请单号    
+ StudyInstanceUID | VARCHAR(128) | NO   |     |         | StudyInstanceUID
+ Modality         | VARCHAR(45)  | YES  |     |         | 设备名字    
+ ModalityType     | VARCHAR(45)  | YES  |     |         | 设备类型    
+ AccNo            | VARCHAR(128) | YES  |     |         | Accesion Number号码
+ status           | INT(10)      | NO   |     | 0       | 状态0:默认1:正常2:删除
+ ctime            | INT(10)      | NO   |     |         | 创建时间    
+ utime            | INT(10)      | YES  |     |         | 更新时间    
+------------------+--------------+------+-----+---------+---------
+

+ 22 - 0
ZSKK_DicomServer/src/main/java/com/zskk/model/_MappingKit.java

@@ -0,0 +1,22 @@
+package com.zskk.model;
+
+import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
+
+/**
+ * Generated by JFinal, do not modify this file.
+ * <pre>
+ * Example:
+ * public void configPlugin(Plugins me) {
+ *     ActiveRecordPlugin arp = new ActiveRecordPlugin(...);
+ *     _MappingKit.mapping(arp);
+ *     me.add(arp);
+ * }
+ * </pre>
+ */
+public class _MappingKit {
+	
+	public static void mapping(ActiveRecordPlugin arp) {
+		arp.addMapping("applyno_studyuid", "id", ApplynoStudyuid.class);
+	}
+}
+

+ 93 - 0
ZSKK_DicomServer/src/main/java/com/zskk/model/base/BaseApplynoStudyuid.java

@@ -0,0 +1,93 @@
+package com.zskk.model.base;
+
+import com.jfinal.plugin.activerecord.Model;
+import com.jfinal.plugin.activerecord.IBean;
+
+/**
+ * Generated by JFinal, do not modify this file.
+ */
+@SuppressWarnings({"serial", "unchecked"})
+public abstract class BaseApplynoStudyuid<M extends BaseApplynoStudyuid<M>> extends Model<M> implements IBean {
+
+	public M setId(java.lang.Integer id) {
+		set("id", id);
+		return (M)this;
+	}
+	
+	public java.lang.Integer getId() {
+		return getInt("id");
+	}
+
+	public M setApplyNo(java.lang.String ApplyNo) {
+		set("ApplyNo", ApplyNo);
+		return (M)this;
+	}
+	
+	public java.lang.String getApplyNo() {
+		return getStr("ApplyNo");
+	}
+
+	public M setStudyInstanceUID(java.lang.String StudyInstanceUID) {
+		set("StudyInstanceUID", StudyInstanceUID);
+		return (M)this;
+	}
+	
+	public java.lang.String getStudyInstanceUID() {
+		return getStr("StudyInstanceUID");
+	}
+
+	public M setModality(java.lang.String Modality) {
+		set("Modality", Modality);
+		return (M)this;
+	}
+	
+	public java.lang.String getModality() {
+		return getStr("Modality");
+	}
+
+	public M setModalityType(java.lang.String ModalityType) {
+		set("ModalityType", ModalityType);
+		return (M)this;
+	}
+	
+	public java.lang.String getModalityType() {
+		return getStr("ModalityType");
+	}
+
+	public M setAccNo(java.lang.String AccNo) {
+		set("AccNo", AccNo);
+		return (M)this;
+	}
+	
+	public java.lang.String getAccNo() {
+		return getStr("AccNo");
+	}
+
+	public M setStatus(java.lang.Integer status) {
+		set("status", status);
+		return (M)this;
+	}
+	
+	public java.lang.Integer getStatus() {
+		return getInt("status");
+	}
+
+	public M setCtime(java.lang.Integer ctime) {
+		set("ctime", ctime);
+		return (M)this;
+	}
+	
+	public java.lang.Integer getCtime() {
+		return getInt("ctime");
+	}
+
+	public M setUtime(java.lang.Integer utime) {
+		set("utime", utime);
+		return (M)this;
+	}
+	
+	public java.lang.Integer getUtime() {
+		return getInt("utime");
+	}
+
+}

+ 307 - 0
ZSKK_DicomServer/src/main/java/com/zskk/service/DicomCMoveService.java

@@ -0,0 +1,307 @@
+package com.zskk.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option.Builder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+import org.dcm4che3.data.Tag;
+import org.dcm4che3.data.UID;
+import org.dcm4che3.data.Attributes;
+import org.dcm4che3.data.ElementDictionary;
+import org.dcm4che3.data.VR;
+import org.dcm4che3.io.DicomInputStream;
+import org.dcm4che3.net.ApplicationEntity;
+import org.dcm4che3.net.Association;
+import org.dcm4che3.net.Connection;
+import org.dcm4che3.net.Device;
+import org.dcm4che3.net.DimseRSPHandler;
+import org.dcm4che3.net.IncompatibleConnectionException;
+import org.dcm4che3.net.pdu.AAssociateRQ;
+import org.dcm4che3.net.pdu.ExtendedNegotiation;
+import org.dcm4che3.net.pdu.PresentationContext;
+import org.dcm4che3.tool.common.CLIUtils;
+import org.dcm4che3.util.SafeClose;
+import org.dcm4che3.util.StringUtils;
+
+public class DicomCMoveService extends Device{
+	
+	private static enum InformationModel {
+        PatientRoot(UID.PatientRootQueryRetrieveInformationModelMOVE, "STUDY"),
+        StudyRoot(UID.StudyRootQueryRetrieveInformationModelMOVE, "STUDY"),
+        PatientStudyOnly(UID.PatientStudyOnlyQueryRetrieveInformationModelMOVERetired, "STUDY"),
+        CompositeInstanceRoot(UID.CompositeInstanceRootRetrieveMOVE, "IMAGE"),
+        HangingProtocol(UID.HangingProtocolInformationModelMOVE, null),
+        ColorPalette(UID.ColorPaletteQueryRetrieveInformationModelMOVE, null);
+
+        final String cuid;
+        final String level;
+
+        InformationModel(String cuid, String level) {
+            this.cuid = cuid;
+            this.level = level;
+       }
+    }
+
+    private static ResourceBundle rb =
+        ResourceBundle.getBundle("org.dcm4che3.tool.movescu.messages");
+
+    private static final int[] DEF_IN_FILTER = {
+        Tag.SOPInstanceUID,
+        Tag.StudyInstanceUID,
+        Tag.SeriesInstanceUID
+    };
+
+    private final ApplicationEntity ae = new ApplicationEntity("cspacsFIR");
+    private final Connection conn = new Connection();
+    private final Connection remote = new Connection();
+    private final AAssociateRQ rq = new AAssociateRQ();
+    private int priority;
+    private String destination;
+    private InformationModel model;
+    private Attributes keys = new Attributes();
+    private int[] inFilter = DEF_IN_FILTER;
+    private Association as;
+
+//    public DicomCMoveService() throws IOException {
+//        super("movescu");
+//        addConnection(conn);
+//        addApplicationEntity(ae);
+//        ae.addConnection(conn);
+//    }
+
+    public final void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public final void setInformationModel(InformationModel model, String[] tss,
+            boolean relational) {
+       this.model = model;
+       rq.addPresentationContext(new PresentationContext(1, model.cuid, tss));
+       if (relational)
+           rq.addExtendedNegotiation(new ExtendedNegotiation(model.cuid, new byte[]{1}));
+       if (model.level != null)
+           addLevel(model.level);
+    }
+
+    public void addLevel(String s) {
+        keys.setString(Tag.QueryRetrieveLevel, VR.CS, s);
+    }
+
+    public final void setDestination(String destination) {
+        this.destination = destination;
+    }
+
+    public void addKey(int tag, String... ss) {
+        VR vr = ElementDictionary.vrOf(tag, keys.getPrivateCreator(tag));
+        keys.setString(tag, vr, ss);
+    }
+
+    public final void setInputFilter(int[] inFilter) {
+        this.inFilter  = inFilter;
+    }
+
+    private static CommandLine parseComandLine(String[] args)
+                throws ParseException {
+            Options opts = new Options();
+            addServiceClassOptions(opts);
+            addKeyOptions(opts);
+            addRetrieveLevelOption(opts);
+            addDestinationOption(opts);
+            CLIUtils.addConnectOption(opts);
+            CLIUtils.addBindOption(opts, "cspacsFIR");
+            CLIUtils.addAEOptions(opts);
+            CLIUtils.addRetrieveTimeoutOption(opts);
+            CLIUtils.addPriorityOption(opts);
+            CLIUtils.addCommonOptions(opts);
+            return CLIUtils.parseComandLine(args, opts, rb, DicomCMoveService.class);
+    }
+
+    @SuppressWarnings("static-access")
+    private static void addRetrieveLevelOption(Options opts) {
+        opts.addOption(Option.builder("L")
+                .hasArg()
+                .argName("PATIENT|STUDY|SERIES|IMAGE|FRAME")
+                .desc(rb.getString("level"))
+                .build());
+   }
+
+    @SuppressWarnings("static-access")
+    private static void addDestinationOption(Options opts) {
+        opts.addOption(Option.builder()
+                .longOpt("dest")
+                .hasArg()
+                .argName("aet")
+                .desc(rb.getString("dest"))
+                .build());
+        
+    }
+
+    @SuppressWarnings("static-access")
+    private static void addKeyOptions(Options opts) {
+        opts.addOption(Option.builder("m")
+                .hasArgs()
+                .argName("attr=value")
+                .valueSeparator('=')
+                .desc(rb.getString("match"))
+                .build());
+        opts.addOption(Option.builder("i")
+                .hasArgs()
+                .argName("attr")
+                .desc(rb.getString("in-attr"))
+                .build());
+    }
+
+    @SuppressWarnings("static-access")
+    private static void addServiceClassOptions(Options opts) {
+        opts.addOption(Option.builder("M")
+                .hasArg()
+                .argName("name")
+                .desc(rb.getString("model"))
+                .build());
+        CLIUtils.addTransferSyntaxOptions(opts);
+        opts.addOption(null, "relational", false, rb.getString("relational"));
+    }
+    
+    @SuppressWarnings("unchecked")
+    public String doMove(String studyuid) {
+        try {
+        	addConnection(conn);
+            addApplicationEntity(ae);
+            ae.addConnection(conn);
+            
+        	String[]str = new String[]{"-c", "cspacsFIR@192.10.10.108:2104","-m","StudyInstanceUID=" + studyuid,"--dest","PACSONLINE"};
+            CommandLine cl = parseComandLine(str);
+            
+            CLIUtils.configureConnect(this.remote, this.rq, cl);
+            CLIUtils.configureBind(conn, ae, cl);
+            CLIUtils.configure(conn, cl);
+            this.remote.setTlsProtocols(conn.getTlsProtocols());
+            this.remote.setTlsCipherSuites(conn.getTlsCipherSuites());
+            configureServiceClass(this, cl);
+            configureKeys(this, cl);
+            this.setPriority(CLIUtils.priorityOf(cl));
+            this.setDestination(destinationOf(cl));
+            ExecutorService executorService =
+                    Executors.newSingleThreadExecutor();
+            ScheduledExecutorService scheduledExecutorService =
+                    Executors.newSingleThreadScheduledExecutor();
+            this.setExecutor(executorService);
+            this.setScheduledExecutor(scheduledExecutorService);
+            try {
+            	
+                this.open();
+                
+                List<String> argList = cl.getArgList();
+                if (argList.isEmpty())
+                	this.retrieve();
+                else
+                    for (String arg : argList)
+                    	this.retrieve(new File(arg));
+            } finally {
+            	this.close();
+                executorService.shutdown();
+                scheduledExecutorService.shutdown();
+            }
+            return "succeed";
+       } catch (ParseException e) {
+            System.err.println("movescu error: " + e.getMessage());
+            System.err.println(rb.getString("try"));
+//            System.exit(2);
+            return "movescu: " + e.getMessage()+rb.getString("try");
+        } catch (Exception e) {
+            System.err.println("movescu error: " + e.getMessage());
+            e.printStackTrace();
+            return "movescu: " + e.getMessage();
+
+//            System.exit(2);
+        }
+    }
+
+    private static void configureServiceClass(DicomCMoveService main, CommandLine cl) throws ParseException {
+        main.setInformationModel(informationModelOf(cl),
+                CLIUtils.transferSyntaxesOf(cl), cl.hasOption("relational"));
+    }
+
+    private static String destinationOf(CommandLine cl) throws ParseException {
+        if (cl.hasOption("dest"))
+            return cl.getOptionValue("dest");
+        throw new ParseException(rb.getString("missing-dest"));
+    }
+
+    private static void configureKeys(DicomCMoveService main, CommandLine cl) {
+        if (cl.hasOption("m")) {
+            String[] keys = cl.getOptionValues("m");
+            for (int i = 1; i < keys.length; i++, i++)
+                main.addKey(CLIUtils.toTag(keys[i - 1]), StringUtils.split(keys[i], '/'));
+        }
+        if (cl.hasOption("L"))
+            main.addLevel(cl.getOptionValue("L"));
+        if (cl.hasOption("i"))
+            main.setInputFilter(CLIUtils.toTags(cl.getOptionValues("i")));
+    }
+
+    private static InformationModel informationModelOf(CommandLine cl) throws ParseException {
+        try {
+            return cl.hasOption("M")
+                    ? InformationModel.valueOf(cl.getOptionValue("M"))
+                    : InformationModel.StudyRoot;
+        } catch(IllegalArgumentException e) {
+            throw new ParseException(MessageFormat.format(
+                    rb.getString("invalid-model-name"),
+                    cl.getOptionValue("M")));
+        }
+    }
+
+    public void open() throws IOException, InterruptedException,
+            IncompatibleConnectionException, GeneralSecurityException {
+        as = ae.connect(conn, remote, rq);
+    }
+
+    public void close() throws IOException, InterruptedException {
+        if (as != null && as.isReadyForDataTransfer()) {
+            as.waitForOutstandingRSP();
+            as.release();
+        }
+    }
+
+    public void retrieve(File f) throws IOException, InterruptedException {
+        Attributes attrs = new Attributes();
+        DicomInputStream dis = null;
+        try {
+            attrs.addSelected(new DicomInputStream(f).readDataset(-1, -1), inFilter);
+        } finally {
+            SafeClose.close(dis);
+        }
+        attrs.addAll(keys);
+        retrieve(attrs);
+    }
+
+    public void retrieve() throws IOException, InterruptedException {
+        retrieve(keys);
+    }
+
+    private void retrieve(Attributes keys) throws IOException, InterruptedException {
+         DimseRSPHandler rspHandler = new DimseRSPHandler(as.nextMessageID()) {
+
+            @Override
+            public void onDimseRSP(Association as, Attributes cmd,
+                    Attributes data) {
+                super.onDimseRSP(as, cmd, data);
+            }
+        };
+
+        as.cmove(model.cuid, priority, keys, null, destination, rspHandler);
+    }
+
+}

+ 2 - 2
ZSKK_DicomServer/src/main/java/com/zskk/service/DicomEchoService.java

@@ -60,8 +60,8 @@ public class DicomEchoService {
         ExecutorService executor = Executors.newSingleThreadExecutor();
         ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
         try {
-        	device = new Device("c-echo-scu");
-            ae = new ApplicationEntity("c-echo-scu");
+        	device = new Device("PACSONLINE");
+            ae = new ApplicationEntity("PACSONLINE");
             conn = new Connection();
             device.addApplicationEntity(ae);
             device.addConnection(conn);

+ 139 - 0
ZSKK_DicomServer/src/main/java/com/zskk/service/InfoService.java

@@ -0,0 +1,139 @@
+package com.zskk.service;
+
+import com.zskk.model.ApplynoStudyuid;
+import com.zskk.util.XmlHelper;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+
+public class InfoService {
+	
+	private static final String PACSVIEW_URL_STR = "http://192.10.10.165/#/pc?studyurl=http://192.10.10.165:8999/query?address=192.10.10.165:9999&study_uid=";
+	
+	public String getOrderInfo(String applyNo) {
+		String studyuidString = null;
+	    ApplynoStudyuid applynoStudyuidCheck = ApplynoStudyuid.dao.findFirst("select * from applyno_studyuid where ApplyNo = ?",applyNo);
+	    if (applynoStudyuidCheck == null || (create_timestamp()-applynoStudyuidCheck.getUtime())>=604800) {
+	    	studyuidString = getOrderInfoFromPACS(applyNo);
+	    	if (studyuidString != null) {
+	    		try {
+					Thread.sleep(6000);
+				} catch (InterruptedException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+				return PACSVIEW_URL_STR + studyuidString;
+			}
+		}else {
+	    	studyuidString = applynoStudyuidCheck.getStudyInstanceUID();
+			return PACSVIEW_URL_STR + studyuidString;
+
+		}
+		return null;
+	}
+
+	private String getOrderInfoFromPACS(String applyNo) {
+		String url = "http://192.10.10.110/CSWebService/CSWebService.asmx/GetOrderInfo";
+		OkHttpClient okHttpClient = new OkHttpClient();
+		StringBuilder sb = new StringBuilder();
+		sb.append("Info=<Body><ApplyNo>");
+		sb.append(applyNo);
+		sb.append("</ApplyNo></Body>");
+
+		RequestBody body = RequestBody.create(sb.toString(), MediaType.get("application/x-www-form-urlencoded"));
+		Request request = new Request.Builder().url(url).post(body).build();
+		try (Response response = okHttpClient.newCall(request).execute()) {
+			String contentString = response.body().string();
+		    XmlHelper xmlHelperStr = XmlHelper.of(contentString);
+		    String content = xmlHelperStr.getString("//string");
+		    XmlHelper xmlHelper = XmlHelper.of(content);
+		    String StudyInstanceUID = xmlHelper.getString("//StudyInstanceUID");
+		    
+		    String AccNo = xmlHelper.getString("//AccNo");
+
+		    String Modality = xmlHelper.getString("//Modality");
+
+		    String ModalityType = xmlHelper.getString("//ModalityType");
+
+		    String ReturnCode = xmlHelper.getString("//ReturnCode");
+
+		    String IsExistImage = xmlHelper.getString("//IsExistImage");
+		    
+		    String ReturnDesc = xmlHelper.getString("//ReturnDesc");
+		    
+		    if (!ReturnCode.equals("0") || IsExistImage.equals("0")) {
+				return null;
+			}
+		    
+		    DicomCMoveService dService =  new DicomCMoveService();  
+			try {
+				String resultString = dService.doMove(StudyInstanceUID);
+				if (resultString.equals("succeed")) {
+					ApplynoStudyuid applynoStudyuidCheck = ApplynoStudyuid.dao.findFirst("select * from applyno_studyuid where ApplyNo=?",applyNo);
+				    
+				    if (applynoStudyuidCheck == null) {
+				    	ApplynoStudyuid applynoStudyuid = new ApplynoStudyuid();
+					    applynoStudyuid.setApplyNo(applyNo);
+					    applynoStudyuid.setStudyInstanceUID(StudyInstanceUID);
+					    applynoStudyuid.setModality(Modality);
+					    applynoStudyuid.setModalityType(ModalityType);
+					    applynoStudyuid.setAccNo(AccNo);
+					    applynoStudyuid.setStatus(1);
+					    applynoStudyuid.setCtime(create_timestamp());
+					    applynoStudyuid.setUtime(create_timestamp());
+					    applynoStudyuid.save();
+					}else {
+						applynoStudyuidCheck.setStatus(1);
+						applynoStudyuidCheck.setUtime(create_timestamp());
+						applynoStudyuidCheck.update();
+					}
+				}else {
+					return null;
+				}
+				
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		    return StudyInstanceUID;
+		} catch (Exception e) {
+			// TODO: handle exception
+			System.out.println(e.toString());
+			return null;
+
+		}
+	}
+	
+	private Integer create_timestamp() {
+		
+		Integer timeInt=Integer.parseInt(Long.toString(System.currentTimeMillis() / 1000));
+		return timeInt;
+	}
+	
+	public static void main(String[] args) {
+		String url = "http://192.10.10.110/CSWebService/CSWebService.asmx/GetOrderInfo";
+		OkHttpClient okHttpClient = new OkHttpClient();
+		StringBuilder sb = new StringBuilder();
+		sb.append("Info=<Body><ApplyNo>");
+		sb.append("2553641");
+		sb.append("</ApplyNo></Body>");
+
+		RequestBody body = RequestBody.create(sb.toString(), MediaType.get("application/x-www-form-urlencoded"));
+		Request request = new Request.Builder().url(url).post(body).build();
+		try (Response response = okHttpClient.newCall(request).execute()) {
+			String content = response.body().string();
+		    XmlHelper xmlHelper = XmlHelper.of(content);
+		    String test = xmlHelper.getString("//string");
+		    XmlHelper xmlHelper2 = XmlHelper.of(test);
+		    String test2 = xmlHelper2.getString("//StudyInstanceUID");
+		    System.out.println(test2);
+		} catch (Exception e) {
+			// TODO: handle exception
+			System.out.println(e.toString());
+		}
+	}
+
+}

+ 2 - 0
ZSKK_DicomServer/src/main/java/com/zskk/service/ServiceFactory.java

@@ -19,6 +19,8 @@ public class ServiceFactory {
 	public static void init(){
 		CLASS_MAP.put(ThreadPoolService.class, 	        Duang.duang(ThreadPoolService.class));
 		CLASS_MAP.put(DicomEchoService.class, 	        Duang.duang(DicomEchoService.class));
+		CLASS_MAP.put(InfoService.class, 	        Duang.duang(InfoService.class));
+
 
 	}
 	

+ 19 - 0
ZSKK_DicomServer/src/main/java/com/zskk/util/Charsets.java

@@ -0,0 +1,19 @@
+package com.zskk.util;
+
+import java.nio.charset.Charset;
+
+/**
+ * 字符集工具类
+ * Author: L.cm
+ * Date: 2016年3月29日 下午3:44:52
+ */
+public class Charsets {
+
+    // 字符集GBK
+    public static final Charset GBK = Charset.forName("GBK");
+    // 字符集ISO-8859-1
+    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+    // 字符集utf-8
+    public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+}

+ 8 - 0
ZSKK_DicomServer/src/main/java/com/zskk/util/ErrorConstant.java

@@ -0,0 +1,8 @@
+package com.zskk.util;
+
+import com.zskk.controller.bean.ResultBean;
+
+public class ErrorConstant {
+	public static final ResultBean ERROR_NOT_FOUND = new ResultBean(100, "未获取到影像");
+	
+}

+ 76 - 0
ZSKK_DicomServer/src/main/java/com/zskk/util/IOUtils.java

@@ -0,0 +1,76 @@
+package com.zskk.util;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+/**
+ * IOUtils
+ * @author L.cm
+ */
+public abstract class IOUtils {
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+    /**
+     * closeQuietly
+     * @param closeable 自动关闭
+     */
+    public static void closeQuietly(Closeable closeable) {
+        try {
+            if (closeable != null) {
+                closeable.close();
+            }
+        } catch (IOException ioe) {
+            // ignore
+        }
+    }
+
+    /**
+     * InputStream to String utf-8
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @return the requested String
+     * @throws NullPointerException if the input is null
+     * @throws IOException if an I/O error occurs
+     */
+    public static String toString(InputStream input) throws IOException {
+        return toString(input, Charsets.UTF_8);
+    }
+
+    /**
+     * InputStream to String
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @param charset  the <code>Charset</code>
+     * @return the requested String
+     * @throws NullPointerException if the input is null
+     * @throws IOException if an I/O error occurs
+     */
+    public static String toString(InputStream input, Charset charset) throws IOException {
+        InputStreamReader in = new InputStreamReader(input, charset);
+        StringBuffer out = new StringBuffer();
+        char[] c = new char[DEFAULT_BUFFER_SIZE];
+        for (int n; (n = in.read(c)) != -1;) {
+            out.append(new String(c, 0, n));
+        }
+        IOUtils.closeQuietly(in);
+        IOUtils.closeQuietly(input);
+        return out.toString();
+    }
+
+    /**
+     * InputStream to File
+     * @param input  the <code>InputStream</code> to read from
+     * @param file the File to write
+     * @throws IOException id异常
+     */
+    public static void toFile(InputStream input, File file) throws IOException {
+        OutputStream os = new FileOutputStream(file);
+        int bytesRead = 0;
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+        while ((bytesRead = input.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        IOUtils.closeQuietly(os);
+        IOUtils.closeQuietly(input);
+    }
+}

+ 241 - 0
ZSKK_DicomServer/src/main/java/com/zskk/util/XmlHelper.java

@@ -0,0 +1,241 @@
+package com.zskk.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * xpath解析xml
+ * <pre>
+ *     文档地址:
+ *     http://www.w3school.com.cn/xpath/index.asp
+ * </pre>
+ */
+public class XmlHelper {
+    private final XPath path;
+    private final Document doc;
+
+    private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory dbf = getDocumentBuilderFactory();
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        doc = db.parse(inputSource);
+        path = getXPathFactory().newXPath();
+    }
+
+    private static XmlHelper create(InputSource inputSource) {
+        try {
+            return new XmlHelper(inputSource);
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        } catch (SAXException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static XmlHelper of(InputStream is) {
+        InputSource inputSource = new InputSource(is);
+        return create(inputSource);
+    }
+
+    public static XmlHelper of(String xmlStr) {
+        StringReader sr = new StringReader(xmlStr.trim());
+        InputSource inputSource = new InputSource(sr);
+        XmlHelper xmlHelper = create(inputSource);
+        IOUtils.closeQuietly(sr);
+        return xmlHelper;
+    }
+
+    private Object evalXPath(String expression, Object item, QName returnType) {
+        item = null == item ? doc : item;
+        try {
+            return path.evaluate(expression, item, returnType);
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 获取String
+     * @param expression 路径
+     * @return String
+     */
+    public String getString(String expression) {
+        return (String) evalXPath(expression, null, XPathConstants.STRING);
+    }
+
+    /**
+     * 获取Boolean
+     * @param expression 路径
+     * @return String
+     */
+    public Boolean getBoolean(String expression) {
+        return (Boolean) evalXPath(expression, null, XPathConstants.BOOLEAN);
+    }
+
+    /**
+     * 获取Number
+     * @param expression 路径
+     * @return {Number}
+     */
+    public Number getNumber(String expression) {
+        return (Number) evalXPath(expression, null, XPathConstants.NUMBER);
+    }
+
+    /**
+     * 获取某个节点
+     * @param expression 路径
+     * @return {Node}
+     */
+    public Node getNode(String expression) {
+        return (Node) evalXPath(expression, null, XPathConstants.NODE);
+    }
+
+    /**
+     * 获取子节点
+     * @param expression 路径
+     * @return NodeList
+     */
+    public NodeList getNodeList(String expression) {
+        return (NodeList) evalXPath(expression, null, XPathConstants.NODESET);
+    }
+
+
+    /**
+     * 获取String
+     * @param node 节点
+     * @param expression 相对于node的路径
+     * @return String
+     */
+    public String getString(Object node, String expression) {
+        return (String) evalXPath(expression, node, XPathConstants.STRING);
+    }
+
+    /**
+     * 获取
+     * @param node 节点
+     * @param expression 相对于node的路径
+     * @return String
+     */
+    public Boolean getBoolean(Object node, String expression) {
+        return (Boolean) evalXPath(expression, node, XPathConstants.BOOLEAN);
+    }
+
+    /**
+     * 获取
+     * @param node 节点
+     * @param expression 相对于node的路径
+     * @return {Number}
+     */
+    public Number getNumber(Object node, String expression) {
+        return (Number) evalXPath(expression, node, XPathConstants.NUMBER);
+    }
+
+    /**
+     * 获取某个节点
+     * @param node 节点
+     * @param expression 路径
+     * @return {Node}
+     */
+    public Node getNode(Object node, String expression) {
+        return (Node) evalXPath(expression, node, XPathConstants.NODE);
+    }
+
+    /**
+     * 获取子节点
+     * @param node 节点
+     * @param expression 相对于node的路径
+     * @return NodeList
+     */
+    public NodeList getNodeList(Object node, String expression) {
+        return (NodeList) evalXPath(expression, node, XPathConstants.NODESET);
+    }
+
+    /**
+     * 针对没有嵌套节点的简单处理
+     * @return map集合
+     */
+    public Map<String, String> toMap() {
+        Element root = doc.getDocumentElement();
+        Map<String, String> params = new HashMap<String, String>();
+
+        // 将节点封装成map形式
+        NodeList list = root.getChildNodes();
+        for (int i = 0; i < list.getLength(); i++) {
+            Node node = list.item(i);
+            if (node instanceof Element) {
+                params.put(node.getNodeName(), node.getTextContent());
+            }
+        }
+        return params;
+    }
+    
+    private static boolean preventedXXE = false;
+
+    private static DocumentBuilderFactory getDocumentBuilderFactory() throws ParserConfigurationException{
+    		DocumentBuilderFactory dbf = XmlHelper.XmlHelperHolder.documentBuilderFactory;
+    		if (!preventedXXE) {
+    			preventXXE(dbf);
+    			preventedXXE = true;
+    		}
+        return dbf;
+    }
+    
+    // https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5
+    private static void preventXXE(DocumentBuilderFactory dbf) throws ParserConfigurationException {
+    		// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
+        // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+
+        // If you can't completely disable DTDs, then at least do the following:
+        // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+        // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+
+        // JDK7+ - http://xml.org/sax/features/external-general-entities 
+        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+
+        // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+        // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+
+        // JDK7+ - http://xml.org/sax/features/external-parameter-entities 
+        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+
+        // Disable external DTDs as well
+        dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+
+        // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+        dbf.setXIncludeAware(false);
+        dbf.setExpandEntityReferences(false);
+    }
+
+    private static XPathFactory getXPathFactory() {
+        return  XmlHelper.XmlHelperHolder.xPathFactory;
+    }
+
+    /**
+     * 内部类单例
+     */
+    private static class XmlHelperHolder {
+        private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        private static XPathFactory xPathFactory = XPathFactory.newInstance();
+    }
+
+}

+ 58 - 0
ZSKK_DicomServer/src/main/java/com/zskk/util/_JFinalDemoGenerator.java

@@ -0,0 +1,58 @@
+package com.zskk.util;
+
+import javax.sql.DataSource;
+import com.jfinal.kit.PathKit;
+import com.jfinal.kit.PropKit;
+import com.jfinal.plugin.activerecord.generator.Generator;
+import com.jfinal.plugin.druid.DruidPlugin;
+import com.zskk.common.ZskkConfig;
+
+/**
+ * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法
+ * 详见 JFinal 俱乐部: http://jfinal.com/club
+ * 
+ * 在数据库表有任何变动时,运行一下 main 方法,极速响应变化进行代码重构
+ */
+public class _JFinalDemoGenerator {
+	
+	public static DataSource getDataSource() {
+		PropKit.use("config.properties");
+		DruidPlugin druidPlugin = ZskkConfig.createZskkDruidPlugin();
+		druidPlugin.start();
+		return druidPlugin.getDataSource();
+	}
+	
+	public static void main(String[] args) {
+		
+		// base model 所使用的包名
+		String baseModelPackageName = "com.zskk.model.base";
+		// base model 文件保存路径
+		String baseModelOutputDir = PathKit.getWebRootPath() + "/src/main/java/com/zskk/model/base";
+		
+		// model 所使用的包名 (MappingKit 默认使用的包名)
+		String modelPackageName = "com.zskk.model";
+		// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)
+		String modelOutputDir = baseModelOutputDir + "/..";
+		
+		// 创建生成器
+		Generator generator = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);
+		// 设置是否生成链式 setter 方法
+		generator.setGenerateChainSetter(false);
+		// 添加不需要生成的表名
+		generator.addExcludedTable("exams","images","series","studies","patient_infos");
+		// 设置是否在 Model 中生成 dao 对象
+		generator.setGenerateDaoInModel(true);
+		// 设置是否生成链式 setter 方法
+		generator.setGenerateChainSetter(true);
+		// 设置是否生成字典文件
+		generator.setGenerateDataDictionary(true);
+		// 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
+		generator.setRemovedTableNamePrefixes("t_");
+		// 生成
+		generator.generate();
+	}
+}
+
+
+
+

+ 3 - 3
ZSKK_DicomServer/src/main/resources/config.properties

@@ -1,5 +1,5 @@
 #Database
-jdbcUrl  = jdbc:mysql://www.pacsonline.cn:3306/pacsonline?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
-user     = pacs
-password = ZSKK@2017~!@#
+jdbcUrl_zskk  = jdbc:mysql://192.10.10.165:3306/pacsonline?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
+user_zskk     = root
+password_zskk = Zskk@2019
 devMode  = true

+ 31 - 0
ZSKK_DicomServer/src/main/resources/org/dcm4che3/tool/movescu/messages.properties

@@ -0,0 +1,31 @@
+usage=movescu [options] -c <aet>@<host>:<port> --dest <aet> [--] [<dicom-file>...]
+try=Try `movescu --help' for more information.
+description=\n\
+The movescu application implements a Service Class User (SCU) for the Query/Retrieve, the \
+Composite Instance Root Retrieve, the Composite Instance Retrieve Without Bulk Data, the \
+Hanging Protocol Query/Retrieve and the Color Palette Query/Retrieve Service Class. movescu \
+only supports retrieve functionality using the C-MOVE message. It sends matching keys to an \
+Service Class Provider (SCP) and waits for responses. Matching keys can be specified in \
+DICOM file(s) -- <dicom-file>... or by options -m.\n\-\n\
+Options:
+example=-\n\
+Examples:\n\
+$ movescu -c DCMQRSCP@localhost:11112 -m StudyInstanceUID=1.2.3.4 --dest STORESCP\n\
+Retrieve from Query/Retrieve Service Class Provider DCMQRSCP listening on local port 11112 the \
+Study with Study Instance UID = 1.2.3.4 to the Storage Service Class Provider STORESCP
+missing-dest=you must specify a move destination by option --dest
+model=specifies Information Model. Supported names: PatientRoot, StudyRoot, PatientStudyOnly, \
+CompositeInstanceRoot, WithoutBulkData, HangingProtocol or ColorPalette. If no Information \
+Model is specified, StudyRoot will be used.
+invalid-model-name={0} is not a supported Information Model name
+level=specifies retrieve level. Use STUDY for PatientRoot, StudyRoot, PatientStudyOnly, and \
+IMAGE for CompositeInstanceRoot by default.
+match=specify matching key. attr can be specified by keyword or tag value \
+(in hex), e.g. StudyInstanceUID or 00200000D. Overrides matching keys \
+specified in DICOM file(s). 
+in-attr=specifies which attribute(s) of given DICOM file(s) dcmfile_in will be included in the \
+C-MOVE RQ. attr can be specified by its keyword or tag value (in hex), e.g.: StudyInstanceUID or \
+00100020. By default, Study Instance UID, Series Instance UID and SOP Instance UID from the \
+file(s) will be included.
+dest=specifies AE title of the Move Destination.
+relational=negotiate relational-retrieve support