跟微软保持适当距离--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

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
<?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配置

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
<?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

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
<?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实现类使用

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
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

服务实现类:

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
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后,再执行其他调用

跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
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


完成服务端代码下载

你可能感兴趣的:(hessian)