zoukankan      html  css  js  c++  java
  • 跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用

    同在一个产业链园区的XX厂因为5台Window2003服务器收到了律师函并且被迫下了12万$的采购单,虽然100万对XXX厂来数不是大数目,但是总有种被打劫的感觉。

    在企业ERP应用中服务层一般都是做成远程调用的,具体Windows平台的技术有WebService,WCF,Remoting等,这里展示的是服务端采用linux 平台下采用Hessian组件实现RPC.

    服务端:
    Web服务器:JBoss,tomcat (weblogic挺美但是不免费啊)
    数据库:mysql(一般erp都用oracle做数据库,当然那个啥费用也是不含糊地)
    客户端:
    逆天的XP(sp3) 加.net4.0 (NND,这个组合量你也收不了多少钱把!)
    VS2010? 我们用180试用版或者那啥notepad

    Hessian+spring配置
    1.web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
      <display-name>HessianTest</display-name>
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:conf/ht-core.xml</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      <servlet>
        <servlet-name>hessionRpc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath*:conf/ht-rpc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>hessionRpc</servlet-name>
        <url-pattern>/rpc/*</url-pattern>
      </servlet-mapping>
    
      <servlet>
        <description></description>
        <display-name>TestSpring</display-name>
        <servlet-name>TestSpring</servlet-name>
        <servlet-class>f.studio.web.servlet.TestSpring</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>TestSpring</servlet-name>
        <url-pattern>/TestSpring</url-pattern>
      </servlet-mapping>
      <filter>
        <display-name>HessianCtxFilter</display-name>
        <filter-name>HessianCtxFilter</filter-name>
        <filter-class>f.studio.web.filter.HessianCtxFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>HessianCtxFilter</filter-name>
        <url-pattern>/rpc/*</url-pattern>
      </filter-mapping>
      
       <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
    </web-app>
    View Code

    2.Service,DAO等spring配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
        
            <bean name="studentServiceImpl"
                class="f.studio.service.impl.StudentServiceImpl" scope="prototype" />
    </beans>
    View Code

    3.Hessian导出层spring配置,因为一个项目里可能使用strut2,Servlet,cxf等服务提供层,但是他们需要共用Service,DAO等
    参考:http://jinnianshilongnian.iteye.com/blog/1602617

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
        <bean name="/studentServiceRpc"
            class="org.springframework.remoting.caucho.HessianServiceExporter">
            <property name="service" ref="studentServiceImpl" />
            <property name="serviceInterface" value="f.studio.service.StudentService" />
        </bean>
        
    </beans>
    View Code

    用户登陆状态问题
    Hessian的C#实现可以自己保存cookie,并且是全局的(应用程序范围)
    服务端尝试使用Hessian提供的ServiceContext获取对Session的引用但是结果总为null,所以写个filter 来自己维护用户登陆Session供Service实现类使用

    package f.studio.web.filter;
    
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import f.studio.util.HessianCtxContainer;
    
    /**
     * Servlet Filter implementation class HessianCtxFilter
     */
    public class HessianCtxFilter implements Filter {
    
        public static final String LOGIN_SESSION_KEY="LOGIN_USER_KEY"; 
        /**
         * Default constructor. 
         */
        public HessianCtxFilter() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see Filter#destroy()
         */
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
         */
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
            HttpSession session = ((HttpServletRequest) request).getSession(true);
            System.out.println("sessionId:" + session.getId());
            try {
                
                Object user = session.getAttribute(LOGIN_SESSION_KEY);
                HessianCtxContainer.setAttribute(LOGIN_SESSION_KEY, user);
                System.out.println("sessionUser:" + user);
                chain.doFilter(request, response);
                
            } finally {
                //移除掉ThreadLocal中Map中的对象防止益出
                //session具备自动移动除功能
                //不要在环境下(cxf,strut2等)使用HessionCtxContainer,避免线程重用时造成混乱
                Object user = HessianCtxContainer.remove(LOGIN_SESSION_KEY);
                session.setAttribute(LOGIN_SESSION_KEY, user);
            }
            
        }
    
        /**
         * @see Filter#init(FilterConfig)
         */
        public void init(FilterConfig fConfig) throws ServletException {
            // TODO Auto-generated method stub
        }
    
    }
    View Code

    服务实现类:

    package f.studio.service.impl;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.omg.PortableInterceptor.USER_EXCEPTION;
    
    import com.caucho.hessian.io.Hessian2Output;
    import com.caucho.services.server.ServiceContext;
    
    import f.studio.domain.Klass;
    import f.studio.domain.QueryStudentInfo;
    import f.studio.domain.StudentInfo;
    import f.studio.service.StudentService;
    import f.studio.util.HessianCtxContainer;
    import f.studio.web.filter.HessianCtxFilter;
    
    public class StudentServiceImpl implements StudentService {
    
        public List<StudentInfo> query(QueryStudentInfo q) {
            
            CheckLogin();
            
            ServletRequest request=  ServiceContext.getContextRequest();
            System.out.println(ServiceContext.getServiceName());
            //HttpSession session= request.getSession(true);
            //session.setAttribute("User", new Date());
            
            System.out.println("ServiceImpHashCode:" + this.hashCode());
            System.out.println(q);
            //if(1==1)throw new RuntimeException("运行错误信息啊");
            List<StudentInfo> list=new ArrayList<StudentInfo>();
            Klass klass=new Klass();
            klass.setId(9999);
            klass.setName("张老师");
            klass.setAddTime(new Date());
            
            for(int i=0;i<10;i++){
                StudentInfo s=new StudentInfo();
                
                //===父类
                s.setRecId(88888);
                s.setCreateDate(new Date());
                //==
                s.setId(i);
                s.setName("张思念" + i);
                s.setSex(i % 5 ==0);
                //===添加两个元素==
                s.getKs().add(klass);
                s.getKs().add(klass);
            
                list.add(s);
            }
            return list;
        }
    
        public String hello(String name) {
                return "Hi " +name;
        }
    
        public void Login(String username, String password) {
            if("Admin".equals(username) && "123".equals(password)){
                HessianCtxContainer.setAttribute(HessianCtxFilter.LOGIN_SESSION_KEY , username);
                return;
            }
            throw new RuntimeException("错误的用户名或密码!");
        }
    
        public static void CheckLogin(){
            
            if(HessianCtxContainer.getAttribute(HessianCtxFilter.LOGIN_SESSION_KEY)==null){
                throw new RuntimeException("未登录或登录超时!");
            }
        }
    }
    View Code

    .net客户端,需要添加对hessianCsharp.dll的引用
    调用一次Login后,再执行其他调用

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using hessiancsharp.client;
    
    namespace HessianTest
    {
        using f.studio.domain;
        using System.Threading;
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
    
    
            private void button1_Click(object sender, EventArgs e)
            {
                try
                {
                    CHessianProxyFactory factory = new CHessianProxyFactory("userName", "password");
                    string url = "http://localhost/HessianTest/rpc/studentServiceRpc";//修改为你的server端地址
                    StudentService test = (StudentService)factory.Create(typeof(StudentService), url);
                    string result = test.hello("大白鲨");
                    var q = new QueryStudentInfo() { BTime = DateTime.Now, Name = "哈哈", Id = 1888, Sex = false };
                    q.Data = new byte[] { 5, 4, 3, 2, 1 };
                    q.CreateDate = DateTime.Now;
                    q.RecId = 99999;
    
                    var list = test.query(q);
                    foreach (var it in list)
                    {
                        Console.WriteLine(it);
                    }
                    Console.WriteLine(result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            
    
            }
    
    
            private void button5_Click(object sender, EventArgs e)
            {
                try
                {
                    CHessianProxyFactory factory = new CHessianProxyFactory("userName", "password");
                    string url = "http://localhost/HessianTest/rpc/studentServiceRpc";//修改为你的server端地址
                    StudentService test = (StudentService)factory.Create(typeof(StudentService), url);
                    test.Login("Admin", "123");
                    
                    Console.WriteLine("登陆成功");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    
        public interface StudentService
        {
             string hello(string name);
             List<StudentInfo> query(QueryStudentInfo q);
             void Login(String usename, String password);
        }
    
    
    
    
    }
    
    namespace f.studio.domain
    {
        public class BaseInfo
        {
            private DateTime? createDate;
    
            public DateTime? CreateDate
            {
                get { return createDate; }
                set { createDate = value; }
            }
            private long? recId;
    
            public long? RecId
            {
                get { return recId; }
                set { recId = value; }
            }
        }
        /// <summary>
        /// 上传时用需要保持命名空间与服务器一致
        /// </summary>
        public class QueryStudentInfo :BaseInfo
        {
            private int id;
            private String name;
            private DateTime? btime;
            private Byte[] data;
            private bool sex;
    
            public int Id
            {
                get { return id; }
                set { id = value; }
    
            }
            public DateTime? BTime
            {
                get { return btime; }
                set { btime = value; }
            }
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
            public Byte[] Data
            {
                get { return data; }
                set { data = value; }
            }
            public bool Sex
            {
                get { return sex; }
                set { sex = value; }
            }
        }
    
    
        /// <summary>
        /// 不能使用public int Id{get;set;}
        /// private 字段名称,大小写需要跟服务端定义一致
        /// [Serializable]标记貌似不是必须的
        /// </summary>
        public class Klass :BaseInfo
        {
            private int id;
            private String name;
            private DateTime? addTime;
    
            public DateTime? AddTime
            {
                get { return addTime; }
                set { addTime = value; }
            }
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
    
            public int Id
            {
                get { return id; }
                set { id = value; }
            }
    
        }
    
    
        public class StudentInfo :BaseInfo
        {
            private string name;
            private bool? sex;
            private long id;
            private byte[] fileData;
    
            public byte[] FileData
            {
                get { return fileData; }
                set { fileData = value; }
            }
            private List<Klass> ks;
    
            public List<Klass> Ks
            {
                get { return ks; }
                set { ks = value; }
            }
    
    
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
    
            public long Id
            {
                get { return id; }
                set { id = value; }
            }
    
    
            public bool? Sex
            {
                get { return sex; }
                set { sex = value; }
            }
            public override string ToString()
            {
                return string.Format("Id:{0},Name:{1},Sex:{2},RecId:{3},CreateDate:{4}", Id, Name, Sex,RecId,CreateDate);
            }
    
        }
    }
    View Code


    完成服务端代码下载

  • 相关阅读:
    k8s访问服务时,解析不了域名
    docker常用常用删除操作
    Linux_修改hosts
    java-深克隆和浅克隆
    Mybatis 中$与#的区别
    mysql-修改字段类型和修改字段名称
    HttpMessageNotReadableException(一)
    log4j2的环境变量使用
    Linux中修改环境变量及生效方法
    转!!mysql order by 中文排序
  • 原文地址:https://www.cnblogs.com/wdfrog/p/3229469.html
Copyright © 2011-2022 走看看