Strona główna > Maven2, NetBeans, Spring Framework 3, Struts2 > NetBeans + Maven: Integracja Spring Framework 3 z Struts2

NetBeans + Maven: Integracja Spring Framework 3 z Struts2

W dzisiejszym poście zaprezentuję jak rozpocząć pracę z Spring Framework 3 oraz Struts2, wykorzystując do tego środowisko NetBeans (u mnie 6.9.1) oraz Maven 2. Jak zwykle zaprezentuję całą ścieżkę, łącznie z problemami jakie napotkałem 😛

Aby utworzyć projekt należy wybrać przejść kolejne kroki kreatora:
New Project -> Maven -> Maven Project

Z listy „Maven Archetypes” wybieramy „Archetypes from Local Respository” i zaznaczamy „Maven Webapp Archetype (1.0)„. W kolejnym oknie wypełniamy odpowiednie pola i po kliknięciu zostanie wygenerowany projekt. Pierwszy krok to dodanie zależności do pliku pom.xml (dostępny w gałęzi „Project Files„).
Do wykonania i uruchomienia projektu potrzebne są podstawowe paczki z org.springframework, paczka struts2-core, oraz plugin pozwalający na współpracę między Spring a Struts.

   <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-asm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>${org.apache.struts.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-convention-plugin</artifactId>
            <version>${org.apache.struts.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-spring-plugin</artifactId>
            <version>${org.apache.struts.version}</version>
        </dependency>
    </dependencies>

Jak widać zamiast wersji bibliotek użyłem ${org.springframework.version} oraz ${org.apache.struts.version}, oczywiście celowo – żeby w jednym miejscu zdeklarować numer wersji:

    <properties>
        <org.springframework.version>3.0.4.RELEASE</org.springframework.version>
        <org.apache.struts.version>2.2.1</org.apache.struts.version>
    </properties>

Po zapisaniu pliku można w menu kontekstowego gałezi „Libraries” wybrać „Download Missing Dependencies„.

Kolejny krok to utworzenie przykładowego kontrolera i konfiguracja Springa oraz Struts.

W tym celu w gałęzi „Source packages” tworzymy dowolną paczkę i dodajemy prostą klasę, niech to będzie klasa z akcją „Hello world”.

package eu.ryznar;

public class Hello {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String execute() {
        return "SUCCESS";
    }
}

W „Web Pages” tworzymy plik success.jsp:

<html>
<body>
<h2>Success</h2>
${message}
</body>
</html>

Teraz czas na konfigurację. W web.xml listener dla Springa oraz filter dla Struts2

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

Przeglądając różne tutoriale możecie trafić na przykład gdzie zamiast org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter została użyta klasa org.apache.struts2.dispatcher.FilterDispatcher. To zależy od wersji Struts2. Od wersji 2.1.3 FilterDispatcher jest oznaczona jako przestarzała.

Następnie w katalogu WEB-INF tworzymy plik applicationContext.xml w którym skonfigurujemy ziarna, w tym przypadku klasę „Hello”.

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="helloClass" class="eu.ryznar.Hello" >
        <property name="message" value="Hello World!" />
    </bean>
</beans>

Następnie również w katalogu WEB-INF tworzymy plik struts.xml w którym definiujemy która klasa wykonuje akcję i zwraca odpowiedni widok.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <package name="default" extends="struts-default">
        <action name="hello" class="helloClass">
            <result name="SUCCESS">/success.jsp</result>
        </action>
    </package>
</struts>

Atrybut „class” nie wskazuje bezpośrenio na klasę eu.ryznar.Hello a na ziarno zdefiniowane w pliku konfiguracyjnym Springa.

Przed uruchomieniem należy ustawić serwer. We właściwościach projektu, w gałęzi „Run” wybieramy serwer Tomcat.
To wszystko, czas uruchomić aplikację. Jednak czeka nas niespodzianka 😉 w konsoli dostaniemy taki oto wyjątek:

2010-10-11 21:01:56 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
2010-10-11 21:01:57 org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter struts2
java.lang.reflect.InvocationTargetException - Class: com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector
File: ContainerImpl.java
Method: inject
Line: 295 - com/opensymphony/xwork2/inject/ContainerImpl.java:295:-1
        at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:428)
        at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69)
        at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:295)
        at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
        at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:115)
        at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3838)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4488)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
        at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:637)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:521)
        at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1359)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:297)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836)
        at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
        at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1500)
        at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:849)
        at org.apache.catalina.manager.ManagerServlet.doGet(ManagerServlet.java:351)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:199)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:558)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:295)
        at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.construct(ContainerImpl.java:431)
        at com.opensymphony.xwork2.inject.ContainerBuilder$5.create(ContainerBuilder.java:207)
        at com.opensymphony.xwork2.inject.Scope$2$1.create(Scope.java:51)
        at com.opensymphony.xwork2.inject.ContainerBuilder$3.create(ContainerBuilder.java:93)
        at com.opensymphony.xwork2.inject.ContainerBuilder$7.call(ContainerBuilder.java:487)
        at com.opensymphony.xwork2.inject.ContainerBuilder$7.call(ContainerBuilder.java:484)
        at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:574)
        at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:484)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.createBootstrapContainer(DefaultConfiguration.java:252)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:193)
        at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:66)
        at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:371)
        at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:415)
        ... 41 more
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:293)
        ... 54 more
Caused by: java.lang.ExceptionInInitializerError
        at com.opensymphony.xwork2.ognl.OgnlValueStackFactory.setContainer(OgnlValueStackFactory.java:85)
        ... 59 more
Caused by: java.lang.IllegalArgumentException: Javassist library is missing in classpath! Please add missed dependency!
        at ognl.OgnlRuntime.(OgnlRuntime.java:165)
        ... 60 more
Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1361)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at ognl.OgnlRuntime.(OgnlRuntime.java:162)
        ... 60 more
2010-10-11 21:01:57 org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext

Co się okazuje w wersji 2.2.1 wykluczono z zależności Javassist, dlatego trzeba dodać zależność ręcznie w pom.xml

        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.9.0.GA</version>
        </dependency>

Próbujemy jescze raz uruchomić projekt. W przeglądarce zostaje otworzony plik index.jsp, jednak my chcemy zobaczyć wynik akcji hello, dlatego w pasku adresu zamiast index.jsp wpisujemy hello.action. Niestety strona się nie wyświetla a w konsoli widzimy kolejny wyjątek.

There is no Action mapped for namespace / and action name helloWorld. - [unknown location]
        at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:189)
        at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:61)
        at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
        at com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
        at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:475)
        at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
        at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
        at java.lang.Thread.run(Thread.java:619)

Tym razem okazuje się że plik struts.xml powinien znajdować się w /WEB-INF/classes/ a nie tak jak teraz bezpośrednio w /WEB-INF/

 

Po tej poprawce projekt uruchomi się poprawnie. Mam nadzieję że wpis pomoże jakiemuś początkującemu programiście 🙂 Jeśli ktoś miałby jakieś uwagi to chętnie je poznam 🙂

Advertisements
  1. 21 lutego 2011 o 14:54

    Za ten hint z przesunieciem STRUTS.XML do podkatalogu masz u mnie pifko 🙂

  2. adrian.chrzastowski
    10 września 2011 o 21:21

    Wprawdzie post ma już rok, ale co tam skomentuje.
    Natrafiłem na Twoj post bo właśnie przerabiam temat integracji SPRING3 i STRUTS2. Tak się składa, że ja również używam mavena do zarządzania swoim projektem. Używam SPRING w wersji:3.0.6.RELEASE, STRUTS: 2.2.3.1 w tej samej plugina integrującego. Przeglądając Twoje rozwiązanie, zauważyłem że umknął Ci jeden bardzo ważny fakt, otóż projekt: struts2-spring-plugin w wersji: 2.2.1 zależy od: spring-beans w wersji: ${struts2.springPlatformVersion}; spring-core w wersji: ${struts2.springPlatformVersion}; spring-context w wersji: ${struts2.springPlatformVersion}; spring-web w wersji: ${struts2.springPlatformVersion}; spring-test w wersji: ${struts2.springPlatformVersion}
    Properta ta zdefiniowana jest w projekcie parent: struts2-parent i ma wartość: 2.5.6, zatem projekt, który stworzyłeś de facto używa dwóch wersji SPRINGA: 3.0.4.RELEASE i 2.5.6.
    Żeby ożywać jednej wersji musisz w definicji zależności struts2-spring-plugin wykluczyć projekty springowe.

  3. 12 września 2011 o 17:49

    @Adrian dzięki za uwagę 🙂

  4. Fry
    25 lipca 2012 o 23:14

    Witam
    Po czym stwierdziłeś że plik struts.xml musi być w folderze WEB-INF/classes/
    Gdzie to widzisz w logach ???
    Twoja podpowiedz jest prawidłowa i nie mam żadnych pretensji, tylko skąd to wiedziałeś, ile ja tutoriali przerobiłem i nigdzie nie pisało o tym folderze a tutoriale za nic w świecie nie chciały działać.

    Pozdrawiam

  5. 29 grudnia 2012 o 19:50

    I comment whenever I especially enjoy a post on a website or if I have something to contribute to the discussion.
    Usually it’s caused by the passion communicated in the post I looked at. And on this article NetBeans + Maven: Integracja Spring Framework 3 z Struts2 Love IT. I was actually moved enough to leave a thought 😉 I do have a few questions for you if it’s okay.
    Is it just me or do some of the remarks come across like left
    by brain dead visitors? 😛 And, if you are posting at other places, I’d like to follow anything new you have to post. Could you list every one of your public sites like your twitter feed, Facebook page or linkedin profile?

  6. Herman
    30 grudnia 2012 o 13:40

    Wonderful post! We will be linking to this particularly great post on our website.

    Keep up the great writing.

  7. 3 maja 2013 o 5:24

    Ahaa, its pleasant conversation on the topic of this piece of writing here at this website, I have read all that,
    so now me also commenting at this place.

  8. 5 maja 2013 o 15:35

    What’s Happening i’m new to this, I stumbled
    upon this I have discovered It positively useful and it has aided me out loads.
    I hope to contribute & assist different users like its
    aided me. Great job.

  9. 6 maja 2013 o 15:43

    I enjoy what you guys are usually up too. This type of clever work
    and reporting! Keep up the wonderful works guys
    I’ve incorporated you guys to blogroll.

  10. 26 czerwca 2013 o 10:00

    I visited several sites but the audio quality for audio songs current at this web
    page is genuinely fabulous.

  11. 17 lipca 2013 o 20:36

    I think the admin of this website is actually working hard in support of his web site, as here every
    material is quality based data.

  12. 25 września 2013 o 10:20

    I just like the helpful info you supply for your articles.
    I will bookmark your blog and check once more right here regularly.
    I’m rather certain I’ll be told many new stuff proper here!
    Best of luck for the next!

  13. 6 sierpnia 2014 o 6:27

    Good day! I could have sworn I’ve been to this blog before but after
    browsing through some of the post I realized
    it’s new to me. Anyways, I’m definitely happy I found it and I’ll be bookmarking
    and checking back often!

  14. 19 sierpnia 2014 o 0:07

    As a visionary leader of luxury products, CHARRIOL offers an entire
    collection of jewelry, watches, and accessories all utilizing
    their signature stainless steel cable-inspired motif. If you
    experience problems with your eyes or vision that are not
    solved by the usual means, this is an excellent visual
    therapy to turn to. Echinacea purpurea (herb) Ferrum metallicum (mineral:
    iron).

  15. 3 września 2014 o 22:01

    And engaging customers shall keep carefully the money coming into your organization anyway!

  16. 20 września 2014 o 17:51

    My main concentrate in on building my own, personal products that you guys can affiliate marketplace for yourselves.

  17. 24 września 2014 o 7:09

    Strona świadczy o interesujących zagadnieniach, zapraszam
    do rozmowy

  18. 2 października 2014 o 5:03

    Każdy z nas zetknął się z faktem, polecam zaznajomienie się z tematem.

  19. 19 października 2014 o 1:24

    Drobiazgowe spojrzenie na kwestię, każdy powinien rozczytać także zapoznać się z motywem.

  20. 11 kwietnia 2015 o 16:45

    I enjoy reading through ann articlee that will mke people think.
    Also, many thawnks foor allowing for me to comment!

  21. 10 września 2015 o 16:34

    Amazing issues here. I am very happy to look your article.
    Thanks a lot and I am looking forward to contact you.
    Will you please drop me a e-mail?

  1. 20 października 2014 o 0:25
  2. 15 sierpnia 2015 o 11:58

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

%d bloggers like this: