简体   繁体   English

GWT + Spring Boot @Autowired 不工作

[英]GWT + Spring Boot @Autowired is not working

I have created a application in GWT + Spring Boot and when I try to use @Autowired - I get NullPointerException .我在 GWT + Spring Boot 中创建了一个应用程序,当我尝试使用@Autowired - 我得到NullPointerException Apparently @Autowired does not work and does not insert the bean in the right place.显然@Autowired不起作用并且没有将 bean 插入到正确的位置。 How can I fix this situation?我该如何解决这种情况?

Exception while dispatching incoming RPC call分派传入的 RPC 调用时出现异常

com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.util.List com.myGWT.springbootapp.client.UserService.list()' threw an unexpected exception: java.lang.NullPointerException com.google.gwt.user.server.rpc.UnexpectedException:服务方法“public abstract java.util.List com.myGWT.springbootapp.client.UserService.list()”引发意外异常:java.lang.NullPointerException

File web.xml文件web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>userService</servlet-name>
        <servlet-class>com.myGWT.springbootapp.server.UserServiceImpl</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>userService</servlet-name>
        <url-pattern>/gwtApp/service</url-pattern>
    </servlet-mapping>


    <welcome-file-list>
        <welcome-file>GWTApp.html</welcome-file>
    </welcome-file-list>
</web-app>

pom.xml pom.xml

<name>spring-boot-app</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->

    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <gwt.version>2.7.0</gwt.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>


        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.4</version>
        </dependency>

        <!-- GWT -->
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-user</artifactId>
            <version>${gwt.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-servlet</artifactId>
            <version>${gwt.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-codeserver</artifactId>
            <version>${gwt.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.gwt</groupId>
            <artifactId>gwt-dev</artifactId>
            <version>${gwt.version}</version>
            <scope>provided</scope>
            <exclusions>
            <exclusion>
                <artifactId>apache-jsp</artifactId>
                <groupId>org.eclipse.jetty</groupId>
            </exclusion>
            </exclusions>
        </dependency>
    </dependencies>



    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>gwt-maven-plugin</artifactId>
                    <version>${gwt.version}</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.5</version>
                </plugin>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>2.4.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>target</directory>
                        </fileset>
                        <fileset>
                            <directory>builds</directory>
                            <includes>
                                <include>**/*.*</include>
                            </includes>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
                <executions>
                    <execution>
                        <id>deploy</id>
                        <phase>deploy</phase>
                        <goals><goal>deploy</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

File UserServiceImpl.java文件UserServiceImpl.java

package com.myGWT.springbootapp.server;

import com.myGWT.springbootapp.client.UserService;
import com.myGWT.springbootapp.entities.User;
import com.myGWT.springbootapp.repositories.UserRepository;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends RemoteServiceServlet implements UserService {

AnnotationConfigWebApplicationContext();

    @Autowired
    private UserRepository repository ;

    @Override
    public List<User> list() {
        return repository.findAll();
    }
}

File UserRepository.java文件UserRepository.java

package com.myGWT.springbootapp.repositories;


import com.myGWT.springbootapp.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

}

File UserService.java文件UserService.java

package com.myGWT.springbootapp.client;

import com.myGWT.springbootapp.entities.User;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;


import java.util.List;

@RemoteServiceRelativePath("service")
public interface UserService extends RemoteService {

  List<User> list();
}

File GWTApp.java文件GWTApp.java

package com.myGWT.springbootapp.client;

import com.myGWT.springbootapp.entities.User;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.view.client.ListDataProvider;

import java.util.List;

public class GWTApp implements EntryPoint {

    private  UserServiceAsync userService = GWT.create(UserService.class);

    private ListDataProvider<User> createTable (CellTable<User> table){
        TextColumn<User> idColumn =new TextColumn<User>() {
            @Override
            public String getValue(User object) {
                return object.getId().toString();
            }
        };
        TextColumn<User> loginColumn =new TextColumn<User>() {
            @Override
            public String getValue(User object) {
                return object.getLogin();
            }
        };
        table.addColumn(idColumn, "Id");
        table.addColumn(loginColumn, "Login");
        final ListDataProvider<User> dataProvider = new ListDataProvider<>();
        dataProvider.addDataDisplay(table);
        this.userService.list(new AsyncCallback<List<User>>() {
            @Override
            public void onFailure(Throwable caught) {
                Window.alert("Error: " + caught.getMessage());
            }

            @Override
            public void onSuccess(List<User> result) {
                dataProvider.getList().addAll(result);

            }
        });
        return dataProvider;
    }

    public void onModuleLoad() {
        CellTable<User> table = new CellTable<>();
        ListDataProvider<User> dataProvider = createTable(table);

        RootPanel.get().add(table);
    }
}

Directory structure of the project项目目录结构

在此处输入图片说明

The short answer is: Spring didn't instantiate your GWT service;简短的回答是:Spring 没有实例化您的 GWT 服务; therefore it can't autowire anything into it.因此它不能自动连接任何东西。

The Jetty container is actually responsible for creating and mapping an instance of UserServiceImpl . Jetty 容器实际上负责创建和映射UserServiceImpl的实例。 That's what your web.xml is describing.这就是你的web.xml所描述的。

Your @Service annotation is indeed creating a Servlet instance within the Spring context as you would expect, but it's not known to Jetty.您的@Service注释确实如您所料在 Spring 上下文中创建了一个 Servlet 实例,但 Jetty 不知道它。 Historically, I have removed the @Service annotation from my RemoteServiceServlet -based services and added the following method to provide @Autowire support:从历史上看,我已经从基于RemoteServiceServlet的服务中删除了 @Service 注释,并添加了以下方法来提供@Autowire支持:

public class UserServiceImpl extends RemoteServiceServlet implements UserService {

...

     @Override
     public void init() throws ServletException {
          super.init();
          SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
     }

...

}

From the SpringBeanAutowiringSupport javadoc :SpringBeanAutowiringSupport javadoc

Process @Autowired injection for the given target object, based on the current root web application context as stored in the ServletContext.根据存储在 ServletContext 中的当前根 Web 应用程序上下文,处理给定目标对象的 @Autowired 注入。

Jetty will call init() during Servlet creation and boom, you're beans come together. Jetty 将在 Servlet 创建和繁荣期间调用init() ,您就是 bean。 This is on the hacky side of things because it bridges two unrelated processes, but it is working for me in production currently.这是在hacky的一面,因为它连接了两个不相关的过程,但它目前在生产中对我有用。

Using a Servlet 3.0+ compliant container you can probably find a way to use WebApplicationInitializer ( javadoc ) to fire up your Spring context via AnnotationConfigWebApplicationContext ( javadoc ) prior to mapping your servlets which would allow you to use the instances from there (this replaces your web.xml ).使用 Servlet 3.0+ 兼容容器,您可能会找到一种方法,在映射您的 servlet 之前,使用WebApplicationInitializer ( javadoc ) 通过AnnotationConfigWebApplicationContext ( javadoc ) 启动您的 Spring 上下文,这将允许您从那里使用实例(这将取代您的web.xml )。

Edit:编辑:

And since you're using Spring Boot you can take a peek at this thread which shows how to map servlets via ServletRegistrationBean : How can I register a secondary servlet with Spring Boot?并且由于您使用的是 Spring Boot,因此您可以查看此线程,该线程显示了如何通过ServletRegistrationBean映射 servlet: How can I register a secondary servlet with Spring Boot? (see checketts's answer) (见checketts的回答)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM