intellij配置EJB專案入門

阿扣扣Zzz發表於2017-01-22

intellij配置EJB專案入門

使用的環境
-jdk1.8
-wildfly10

在intellij上配置一個入門級的EJB專案竟然浪費了一天時間,感覺自己碰到了所有網上提到的容易出現的問題(還是笨啊喂 –>_–>),感覺要記錄下來,也防止自己以後再犯


intellij新建ejb專案的流程

1 建立一個總的容器project

新建一個java專案(就是簡單的java專案別多想。。。),命名為ejb

2 建立伺服器端module

右擊ejb專案->new->module->勾選javaWeb和EJB->命名為HelloWorldEJB->一路next到finish
新建專案截圖
在src中新建package,命名為edu.nju.session.stateless,在包下新建一個介面,命名為HelloWorld,程式碼為

package edu.nju.session.stateless;

import javax.ejb.Remote;

@Remote
public interface HelloWorld {
    public String SayHello(String name);
}

除此之外,右擊該包,選擇new->stateless Session bean->命名為HelloWorld
程式碼如下

package edu.nju.session.stateless;

import javax.ejb.Stateless;

@Stateless(name = "HelloWorldEJB")
public class HelloWorldBean implements HelloWorld{
    public HelloWorldBean() {
    }

    @Override
    public String SayHello(String name){
        return name+", Hello World.  Welcome to EJB3!";
    }
}

部署伺服器,選擇圖中
這裡寫圖片描述
藍線圈起來的下拉框,選擇edit Configuration
這裡寫圖片描述
點選左上角的+,選擇jboss->local->新建之後命名為local->選擇右邊的Deployment選項卡->選擇右側+->選擇war exploded(注意這裡一定要是web Deployment)->一路next即可

執行配置好的server,執行完畢後在瀏覽器輸入localhost:8080顯示介面如下
這裡寫圖片描述

最終伺服器端的目錄為
這裡寫圖片描述
至此,伺服器端就配置好了,接下來對客戶端進行配置

3 客戶端module

在ejb專案裡新建midule,選擇ejb專案(網上說選擇java專案即可,但是在我的intellij裡,如果選擇java專案的話就沒有ejb支援了),命名為HelloWorldClient

新建lib資料夾,將server端的javax.ejb-api.jar複製到lib資料夾下,然後從JBoss安裝路徑中,bin\client目錄中複製jboss-client.jar。

新建package:edu.nju.session
在該package下新建三個包,分別為client, factory, stateless(注意,這個包名必須為stateless,要和伺服器端的介面所在包名相同)
stateless中,將伺服器端的HelloWorld介面複製過來,factory中新建類EJBFactory,程式碼如下

package edu.nju.session.factory;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.rmi.Naming;
import java.util.Hashtable;
import java.util.Properties;

public class EJBFactory {
    public static Object getEJB(String jndipath){
        try{
            Properties jndiProps = new Properties();
            jndiProps.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");
            jndiProps.put("jboss.naming.client.ejb.context", true);

            final Context context = new InitialContext(jndiProps);
            return context.lookup(jndipath);
        }catch (NamingException e){
            e.printStackTrace();
        }
        return null;
    }
}

client包中新建類HelloWorldClient,程式碼如下

package edu.nju.session.client;

import edu.nju.session.factory.EJBFactory;
import edu.nju.session.stateless.HelloWorld;

/**
 * Created by 張文玘 on 2017/1/22.
 */
public class HelloWorldClient {
    public static void main(String[] args) {
        HelloWorld hello = (HelloWorld) EJBFactory.getEJB(
                "ejb:/HelloWorldEJB_war_exploded/HelloWorldEJB!edu.nju.session.stateless.HelloWorld"
        );
        if(hello!=null){
            System.out.println("Obtained a remote stateless session bean helloBean for invocation");
        }
        System.out.println(hello.SayHello("Mary2"));
    }
}

在src資料夾下新建jboss-ejb-client.properties檔案,配置如下

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.two.host=localhost
remote.connection.two.port=8080
remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=jboss使用者名稱
remote.connection.default.password=jboss密碼

右擊HelloWorldClient,選擇run就可以執行了,沒有意外的話輸出應該為

這裡寫圖片描述

客戶端目錄為
這裡寫圖片描述

過程中遇到的問題

說起來好像很簡單的樣子,可自己這馬大哈啥時候能改
容易碰到的錯誤:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
在網上搜的時候很多都說的是我的jndiProps設定的屬性不夠明確,但是按照網上的去改的時候又沒有用,發現網上說的都是jboss以前的版本,現在的新版本不需要那麼麻煩,只需要設
jndiProps.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");即可
那麼為什麼會報這個錯呢?
還是因為對intellij不夠了解,老師的教程(eclipse版本)裡說的是要把jboss安裝目錄下/bin/client下的jboss-client.jar匯入到庫,自己以為是直接複製進lib資料夾就可以了,但是這是錯的,要從file下點選project structure,選擇module,選擇右側的Dependencies選項卡,點選右側的+選擇jar並選擇目錄下的jboss-client.jar,在彈出的對話方塊裡選擇HelloWorldClient專案(即將這個jar檔案配置到客戶端)

Java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:CustomView, moduleName:SecurityDelegateEJB, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@12e5a8e
at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798)
一定要注意jboss-ejb-client.properties檔案的位置
一定要注意jboss-ejb-client.properties檔案的位置
一定要注意jboss-ejb-client.properties檔案的位置
重要的事情說三遍也不嫌多,一定要放到src檔案下,傻得放到客戶端根目錄下也是蠢得不行。。。

如果你確認自己的jboss-ejb-client.properties檔案的位置確實是在src檔案下,卻還是報上面的那個問題的話,要注意你的jndi名稱怎麼起
這裡寫圖片描述
就是上文中說的EJBFactory.getEJB後面的字串,由於還是j2ee菜鳥,不是很懂這個到底是要幹什麼,但是每個欄位大概的意思是知道的
首先一定要用ejb:/開頭,後面的是伺服器端的輸出目錄/對應介面的實現類(即剛才的HelloWorldBean,這裡由於定義了name屬性所以使用定義的名字)/Remote介面的路徑
這個估計是提供一個對接視窗的意思吧。。。
那麼錯在哪裡呢?
錯就在伺服器端的輸出目錄,老師的教程裡寫的是HelloWorldEJB,這裡不應該是伺服器端的module名,而應該是伺服器端的輸出目錄,可以在整個專案的out資料夾中找到,如圖
這裡寫圖片描述
終於解決了所有問題!不過還有很多不懂的地方,需要繼續學習,加油!

更多錯誤情況參考
http://blog.csdn.net/taiyangdao/article/details/50820318
intellij建立ejb專案傳送門(我的還是不夠詳細)
http://www.cnblogs.com/yangyquin/p/5328344.html

2017.1.23更新
今天寫一個stateful的bean的例子的時候又爆了錯。。。
錯誤為:

javax.naming.NamingException: Failed to create proxy [Root exception is java.lang.IllegalStateException: EJBCLIENT000024: No EJB receiver available for handling [appName:, moduleName:MyAccountEJB, distinctName:] combination]
    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.createEjbProxy(EjbNamingContext.java:206)
    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.lookup(EjbNamingContext.java:187)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at edu.nju.session.stateful.EJBFactory.getEJB(EJBFactory.java:21)
    at edu.nju.session.stateful.MyAccountClient.main(MyAccountClient.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.IllegalStateException: EJBCLIENT000024: No EJB receiver available for handling [appName:, moduleName:MyAccountEJB, distinctName:] combination
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:873)
    at org.jboss.ejb.client.EJBClient.createSessionWithPossibleRetries(EJBClient.java:222)
    at org.jboss.ejb.client.EJBClient.createSession(EJBClient.java:202)
    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.doCreateProxy(EjbNamingContext.java:227)
    at org.jboss.ejb.client.naming.ejb.EjbNamingContext.createEjbProxy(EjbNamingContext.java:204)
    ... 9 more
Exception in thread "main" java.lang.NullPointerException
    at edu.nju.session.stateful.MyAccountClient.main(MyAccountClient.java:17)

這個錯還是和jndi的查詢名稱有關係,要特別注意傳給EJBFactory的jndipath是否正確,intellij建立statefull bean的時候自動為它加了name的屬性,所以bean-name不能用原來類的名稱,要用name裡定義的名稱(汗。。。同一個地方跌倒兩次,以後一定要仔細仔細再仔細!

相關文章