jersey put 服务_项目学生:带有Jersey的Web服务服务器

jersey put 服务

这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client业务层带有Spring Data的持久性

RESTful Web应用程序洋葱的第二层是Web服务服务器。 它应该是一个薄层,用于包装对业务层的调用,但不对其自身进行大量处理。 这篇文章有很多代码,但主要是测试类。

设计决策

泽西岛 -我将泽西岛用于REST服务器。 我考虑了替代方案-Spring MVCNetty等,但出于与客户相同的原因,决定选择Jersey。 它轻巧,不会限制开发人员。

依赖注入 –我需要依赖注入,这意味着我需要确定一个框架:Spring,EJB3,Guice等。我已经知道我将在持久层中使用Spring Data ,因此使用它很容易春天的框架。 我仍然会谨慎地最小化该框架上的任何依赖关系(ha!),以实现最大的灵活性。

局限性

球衣 –我不知道球衣将如何处理高负荷。 这是REST服务器必须是业务层的薄包装的关键原因-如果有必要,更改库将相对容易。

用户权限 –没有尝试将对某些方法的访问限制为特定用户或主机。 这应该由业务层来处理,而安全性异常将由REST服务器转换为FORBIDDEN状态代码。

泽西REST服务器

REST API是我们早期的设计文档之一。 对于服务器,这意味着我们从REST服务器开始而不是从业务层API开始实现该层。 实际上,REST服务器在业务层API中定义了必要的方法。

与标准的REST CRUD API有一个小的偏差:对象是使用POST而不是PUT创建的,因为后者的语义是完全按照提供的方式创建了对象。 我们无法做到这一点–出于安全原因,我们从不公开内部ID,也不得接受用户定义的UUID。 这意味着我们将违反REST API合同,因此我们改用POST。

还有一个小作弊:CRUD合同仅需要具有创建或更新对象的能力。 这意味着我们只需给出路径就可以找出所需的操作–我们不需要添加特定的“操作”字段。 随着我们将实现扩展到不仅仅包括CRUD动作,这可能会改变。

继续执行代码...

@Service
@Path("/course")
public class CourseResource extends AbstractResource {
    private static final Logger log = Logger.getLogger(CourseResource.class);
    private static final Course[] EMPTY_COURSE_ARRAY = new Course[0];

    @Context
    UriInfo uriInfo;

    @Context
    Request request;

    @Resource
    private CourseService service;

    /**
     * Default constructor.
     */
    public CourseResource() {

    }

    /**
     * Unit test constructor.
     * 
     * @param service
     */
    CourseResource(CourseService service) {
        this.service = service;
    }

    /**
     * Get all Courses.
     * 
     * @return
     */
    @GET
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    public Response findAllCourses() {
        log.debug("CourseResource: findAllCourses()");

        Response response = null;
        try {
            List<Course> courses = service.findAllCourses();

            List<Course> results = new ArrayList<Course>(courses.size());
            for (Course course : courses) {
                results.add(scrubCourse(course));
            }

            response = Response.ok(results.toArray(EMPTY_COURSE_ARRAY)).build();
        } catch (Exception e) {
            if (!(e instanceof UnitTestException)) {
                log.info("unhandled exception", e);
            }
            response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }

        return response;
    }

    /**
     * Create a Course.
     * 
     * @param req
     * @return
     */
    @POST
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    public Response createCourse(Name req) {
        log.debug("CourseResource: createCourse()");

        final String name = req.getName();
        if ((name == null) || name.isEmpty()) {
            return Response.status(Status.BAD_REQUEST).entity("'name' is required").build();
        }

        Response response = null;

        try {
            Course course = service.createCourse(name);
            if (course == null) {
                response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
            } else {
                response = Response.created(URI.create(course.getUuid())).entity(scrubCourse(course)).build();
            }
        } catch (Exception e) {
            if (!(e instanceof UnitTestException)) {
                log.info("unhandled exception", e);
            }
            response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }

        return response;
    }

    /**
     * Get a specific Course.
     * 
     * @param uuid
     * @return
     */
    @Path("/{courseId}")
    @GET
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    public Response getCourse(@PathParam("courseId") String id) {
        log.debug("CourseResource: getCourse()");

        Response response = null;
        try {
            Course course = service.findCourseByUuid(id);
            response = Response.ok(scrubCourse(course)).build();
        } catch (ObjectNotFoundException e) {
            response = Response.status(Status.NOT_FOUND).build();
        } catch (Exception e) {
            if (!e instanceof UnitTestException)) {
                log.info("unhandled exception", e);
            }
            response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }

        return response;
    }

    /**
     * Update a Course.
     * 
     * FIXME: what about uniqueness violations?
     * 
     * @param id
     * @param req
     * @return
     */
    @Path("/{courseId}")
    @POST
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    public Response updateCourse(@PathParam("courseId") String id, Name req) {
        log.debug("CourseResource: updateCourse()");

        final String name = req.getName();
        if ((name == null) || name.isEmpty()) {
            return Response.status(Status.BAD_REQUEST).entity("'name' is required").build();
        }

        Response response = null;
        try {
            final Course course = service.findCourseByUuid(id);
            final Course updatedCourse = service.updateCourse(course, name);
            response = Response.ok(scrubCourse(updatedCourse)).build();
        } catch (ObjectNotFoundException exception) {
            response = Response.status(Status.NOT_FOUND).build();
        } catch (Exception e) {
            if (!(e instanceof UnitTestException)) {
                log.info("unhandled exception", e);
            }
            response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }

        return response;
    }

    /**
     * Delete a Course.
     * 
     * @param id
     * @return
     */
    @Path("/{courseId}")
    @DELETE
    public Response deleteCourse(@PathParam("courseId") String id) {
        log.debug("CourseResource: deleteCourse()");

        Response response = null;
        try {
            service.deleteCourse(id);
            response = Response.noContent().build();
        } catch (ObjectNotFoundException exception) {
            response = Response.noContent().build();
        } catch (Exception e) {
            if (!(e instanceof UnitTestException)) {
                log.info("unhandled exception", e);
            }
            response = Response.status(Status.INTERNAL_SERVER_ERROR).build();
        }

        return response;
    }
}

该实现告诉我们,我们需要三件事:

  • 服务API(CourseService)
  • 请求参数类(名称)
  • 洗涤器(scrubCourse)

我没有显示完整的日志记录。 必须清除请求参数,以避免日志污染。 。 作为一个简单的示例,请考虑使用写入SQL数据库的记录器,以简化分析。 这个记录器的一个简单的实现-不使用位置参数-将允许通过精心设计的请求参数进行SQL注入!

OWASP ESAPI包含可用于日志清理的方法。 我没有包含在这里,因为设置起来有些麻烦。 (应该很快就会在签入代码中。)

为什么要登录到数据库? 一种好的做法是记录到达服务器层的所有未处理的异常-您永远都不想依靠用户来报告问题,而且写入日志文件的错误很容易被忽略。 相反,使用简单工具可以轻松检查写入数据库的报告。

发生未处理的异常时,高级开发人员甚至可以创建新的错误报告。 在这种情况下,至关重要的是维护一个单独的异常数据库,以避免提交重复的条目和使开发人员不知所措。 (数据库可以包含每个异常的详细信息,但错误报告系统每个异常类+堆栈跟踪仅应有一个错误报告。)

服务API

CRUD操作的服务API很简单。

public interface CourseService {
    List<Course> findAllCourses();

    Course findCourseById(Integer id);

    Course findCourseByUuid(String uuid);

    Course createCourse(String name);

    Course updateCourse(Course course, String name);

    void deleteCourse(String uuid);
}

该API还包含一个ObjectNotFoundException。 (这应该扩展为包括找不到的对象的类型。)

public class ObjectNotFoundException extends RuntimeException {
	private static final long serialVersionUID = 1L;

	private final String uuid;

	public ObjectNotFoundException(String uuid) {
		super("object not found: [" + uuid + "]");
		this.uuid = uuid;
	}

	public String getUuid() {
		return uuid;
	}
}

如上所述,我们最终还需要一个UnauthorizedOperationException。

请求参数

请求参数是封装了POST负载的简单POJO。

@XmlRootElement
public class Name {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

学生和教师也需要电子邮件地址。

@XmlRootElement
public class NameAndEmailAddress {
    private String name;
    private String emailAddress;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
}

最终的应用程序将具有大量的请求参数类。

洗涤塔

洗涤塔具有三个目的。 首先,它删除了不应提供给客户端的敏感信息,例如内部数据库标识符。

其次,它可以防止由于引入集合而导致大量的数据库转储。 例如,一个学生应包括当前部分的列表,但每个部分都有已注册的学生和教师的列表。 这些学生和教师中的每一个都有自己的当前部分列表。 进行泡沫,冲洗,重复,最终将整个数据库转储以响应单个查询。

解决方案是仅包含有关每个可以独立查询的对象的浅层信息。 例如,一个学生将拥有当前部分的列表,但是这些部分将仅包含UUID和名称。 一条很好的经验法则是,清理后的集合应完全包含将在下拉列表和表示表中使用的信息,仅此而已。 演示列表可以包含链接(或AJAX操作),以根据需要提取其他信息。

最后,这是执行HTML编码和清理的好地方。 应该清除返回的值,以防止跨站点脚本(CSS)攻击

public abstract class AbstractResource {

    /**
     * Scrub 'course' object.
     *
     * FIXME add HTML scrubbing and encoding for string values!
     */	
    public Course scrubCourse(final Course dirty) {
        final Course clean = new Course();
        clean.setUuid(dirty.getUuid());
        clean.setName(dirty.getName());
        // clean.setSelf("resource/" + dirty.getUuid());
        return clean;
    }
}

配置类

我们有两个配置类。 第一个始终由服务器使用,第二个仅在集成测试期间由服务器使用。 后者的配置(和引用的类)位于集成测试源树中。

我更喜欢使用配置类(在Spring 3.0中引入),因为它们提供了最大的灵活性-例如,我可以根据运行应用程序或环境变量的用户有条件地定义bean-并允许我仍然包括标准配置文件。

@Configuration
@ComponentScan(basePackages = { "com.invariantproperties.sandbox.student.webservice.server.rest" })
@ImportResource({ "classpath:applicationContext-rest.xml" })
// @PropertySource("classpath:application.properties")
public class RestApplicationContext {

    @Resource
    private Environment environment;
}

Spring 3.1引入了配置文件。 它们可以工作-但是我正在使用的具有弹簧意识的jersey servlet似乎无法正确设置活动概要文件。

@Configuration
//@Profile("test")
public class RestApplicationContextTest {

    @Bean
    StudentService studentService() {
        return new DummyStudentService();
    }
}

web.xml

现在,我们有足够的资源来实现我们的Web服务器。 使用的servlet是启用了spring的Jersey servlet,它使用contextClass参数中给出的配置类。 (也可以使用配置文件,但不能使用配置类和文件的组合。)

该Servlet还包含spring.profiles.active的定义。 目的是通过spring 3.1 @Profile注释有条件地在RestApplicationContextTest中包含定义,但我无法使其正常工作。 我把它留给以后参考。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>Project Student Webservice</display-name>

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.invariantproperties.sandbox.student.webservice.server.config.RestApplicationContext
            com.invariantproperties.sandbox.student.webservice.server.config.RestApplicationContextTest
        </param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>REST dispatcher</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>spring.profiles.active</param-name>
            <param-value>test</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>REST dispatcher</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

单元测试

单元测试很简单。

public class CourseResourceTest {
    private Course physics = new Course();
    private Course mechanics = new Course();

    @Before
    public void init() {
        physics.setId(1);
        physics.setName("physics");
        physics.setUuid(UUID.randomUUID().toString());

        mechanics.setId(1);
        mechanics.setName("mechanics");
        mechanics.setUuid(UUID.randomUUID().toString());
    }

    @Test
    public void testFindAllCourses() {
        final List<Course> expected = Arrays.asList(physics);

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findAllCourses()).thenReturn(expected);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.findAllCourses();

        assertEquals(200, response.getStatus());
        final Course[] actual = (Course[]) response.getEntity();
        assertEquals(expected.size(), actual.length);
        assertNull(actual[0].getId());
        assertEquals(expected.get(0).getName(), actual[0].getName());
        assertEquals(expected.get(0).getUuid(), actual[0].getUuid());
    }

    @Test
    public void testFindAllCoursesEmpty() {
        final List<Course> expected = new ArrayList<>();

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findAllCourses()).thenReturn(expected);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.findAllCourses();

        assertEquals(200, response.getStatus());
        final Course[] actual = (Course[]) response.getEntity();
        assertEquals(0, actual.length);
    }

    @Test
    public void testFindAllCoursesFailure() {
        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findAllCourses()).thenThrow(
                new UnitTestException();

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.findAllCourses();

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testGetCourse() {
        final Course expected = physics;

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findCourseByUuid(expected.getUuid())).thenReturn(expected);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.getCourse(expected.getUuid());

        assertEquals(200, response.getStatus());
        final Course actual = (Course) response.getEntity();
        assertNull(actual.getId());
        assertEquals(expected.getName(), actual.getName());
        assertEquals(expected.getUuid(), actual.getUuid());
    }

    @Test
    public void testGetCourseMissing() {
        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findCourseByUuid(physics.getUuid())).thenThrow(
                new ObjectNotFoundException(physics.getUuid()));

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.getCourse(physics.getUuid());

        assertEquals(404, response.getStatus());
    }

    @Test
    public void testGetCourseFailure() {
        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findCourseByUuid(physics.getUuid())).thenThrow(
                new UnitTestException();

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.getCourse(physics.getUuid());

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testCreateCourse() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.createCourse(name.getName())).thenReturn(expected);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(201, response.getStatus());
        final Course actual = (Course) response.getEntity();
        assertNull(actual.getId());
        assertEquals(expected.getName(), actual.getName());
    }

    @Test
    public void testCreateCourseBlankName() {
        final Course expected = physics;
        final Name name = new Name();

        final CourseService service = Mockito.mock(CourseService.class);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(400, response.getStatus());
    }

    /**
     * Test handling when the course can't be created for some reason. For now
     * the service layer just returns a null value - it should throw an
     * appropriate exception.
     */
    @Test
    public void testCreateCourseProblem() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.createCourse(name.getName())).thenReturn(null);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testCreateCourseFailure() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.createCourse(name.getName())).thenThrow(
                new UnitTestException();

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testUpdateCourse() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(mechanics.getName());
        final Course updated = new Course();
        updated.setId(expected.getId());
        updated.setName(mechanics.getName());
        updated.setUuid(expected.getUuid());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.findCourseByUuid(expected.getUuid())).thenReturn(expected);
        when(service.updateCourse(expected, name.getName()))
                .thenReturn(updated);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.updateCourse(expected.getUuid(),
                name);

        assertEquals(200, response.getStatus());
        final Course actual = (Course) response.getEntity();
        assertNull(actual.getId());
        assertEquals(mechanics.getName(), actual.getName());
        assertEquals(expected.getUuid(), actual.getUuid());
    }

    /**
     * Test handling when the course can't be updated for some reason. For now
     * the service layer just returns a null value - it should throw an
     * appropriate exception.
     */
    @Test
    public void testUpdateCourseProblem() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.updateCourse(expected, name.getName())).thenReturn(null);

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testUpdateCourseFailure() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        when(service.updateCourse(expected, name.getName())).thenThrow(
                new UnitTestException();

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.createCourse(name);

        assertEquals(500, response.getStatus());
    }

    @Test
    public void testDeleteCourse() {
        final Course expected = physics;

        final CourseService service = Mockito.mock(CourseService.class);
        doNothing().when(service).deleteCourse(expected.getUuid());

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.deleteCourse(expected.getUuid());

        assertEquals(204, response.getStatus());
    }

    @Test
    public void testDeleteCourseMissing() {
        final Course expected = physics;
        final Name name = new Name();
        name.setName(expected.getName());

        final CourseService service = Mockito.mock(CourseService.class);
        doThrow(new ObjectNotFoundException(expected.getUuid())).when(service)
                .deleteCourse(expected.getUuid());

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.deleteCourse(expected.getUuid());

        assertEquals(204, response.getStatus());
    }

    @Test
    public void testDeleteCourseFailure() {
        final Course expected = physics;

        final CourseService service = Mockito.mock(CourseService.class);
        doThrow(new UnitTestException()).when(service)
                .deleteCourse(expected.getUuid());

        final CourseResource resource = new CourseResource(service);
        final Response response = resource.deleteCourse(expected.getUuid());

        assertEquals(500, response.getStatus());
    }
}

整合测试

问题: REST服务器集成测试是否应该使用实时数据库?

答:这是一个技巧问题。 我们都需要。

总体架构包含三个Maven模块。 我们前面介绍了student-ws-client,今天介绍了Student-ws-server。 每个都创建一个.jar文件。 第三个模块-student-ws-webapp-创建实际的.war文件。 学生-ws-服务器模块的集成测试应使用虚拟服务层,而学生-ws-webapp模块的集成测试应使用完整堆栈。

我们从集成测试开始,该集成测试反映了客户端模块中的单元测试。

public class CourseRestServerIntegrationTest {

    CourseRestClient client = new CourseRestClientImpl(
            "http://localhost:8080/rest/course/");

    @Test
    public void testGetAll() throws IOException {
        Course[] courses = client.getAllCourses();
        assertNotNull(courses);
    }

    @Test(expected = ObjectNotFoundException.class)
    public void testUnknownCourse() throws IOException {
        client.getCourse("missing");
    }

    @Test
    public void testLifecycle() throws IOException {
        final String physicsName = "Physics 201";
        final Course expected = client.createCourse(physicsName);
        assertEquals(physicsName, expected.getName());

        final Course actual1 = client.getCourse(expected.getUuid());
        assertEquals(physicsName, actual1.getName());

        final Course[] courses = client.getAllCourses();
        assertTrue(courses.length > 0);

        final String mechanicsName = "Newtonian Mechanics 201";
        final Course actual2 = client.updateCourse(actual1.getUuid(),
                mechanicsName);
        assertEquals(mechanicsName, actual2.getName());

        client.deleteCourse(actual1.getUuid());
        try {
            client.getCourse(expected.getUuid());
            fail("should have thrown exception");
        } catch (ObjectNotFoundException e) {
            // do nothing
        }
    }
}

我们还需要一个虚拟服务类,该类可以实现足以支持我们的集成测试的功能。

public class DummyCourseService implements CourseService {
    private Map cache = Collections.synchronizedMap(new HashMap<String, Course>());

    public List<Course> findAllCourses() {
        return new ArrayList(cache.values());
    }

    public Course findCourseById(Integer id) {
        throw new ObjectNotFoundException(null);    	
    }

    public Course findCourseByUuid(String uuid) {
        if (!cache.containsKey(uuid)) {
            throw new ObjectNotFoundException(uuid);    	
        }
        return cache.get(uuid);
    }

    public Course createCourse(String name) {
        Course course = new Course();
        course.setUuid(UUID.randomUUID().toString());
        course.setName(name);
        cache.put(course.getUuid(), course);
        return course;
    }

    public Course updateCourse(Course oldCourse, String name) {
        if (!cache.containsKey(oldCourse.getUuid())) {
            throw new ObjectNotFoundException(oldCourse.getUuid());    	    		
        }

        Course course = cache.get(oldCourse.getUuid());
        course.setUuid(UUID.randomUUID().toString());
        course.setName(name);
        return course;    	
    }

    public void deleteCourse(String uuid) {
        if (cache.containsKey(uuid)) {
            cache.remove(uuid);
        }
    }
}

pom.xml

pom.xml文件应包含一个用于运行嵌入式码头或tomcat服务器的插件。 作为集成测试的一部分,高级用户可以旋转和拆除嵌入式服务器-请参阅更新。

<build>
    <plugins>

        <!-- Run the application using "mvn jetty:run" -->
        <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
            <version>6.1.16</version> <!-- ancient! -->
            <configuration>
                <!-- Log to the console. -->
                <requestLog implementation="org.mortbay.jetty.NCSARequestLog">
                    <!-- This doesn't do anything for Jetty, but is a workaround for a 
                        Maven bug that prevents the requestLog from being set. -->
                    <append>true</append>
                </requestLog>
                <webAppConfig>
                    <contextPath>/</contextPath>
                    <extraClasspath>${basedir}/target/test-classes/</extraClasspath>
                </webAppConfig>
            </configuration>
        </plugin>
    </plugins>
</build>

更新资料

经过更多研究之后,我进行了配置以在集成测试期间设置和拆除码头服务器。 此配置使用非标准端口,因此我们无需关闭同时运行的另一个码头或tomcat实例即可运行它。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <build>
        <plugins>

            <!-- Run the application using "mvn jetty:run" -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.1.0.v20131115</version>
                <configuration>
                    <webApp>
                        <extraClasspath>${basedir}/target/test-classes/</extraClasspath>
                    </webApp>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <stopPort>18005</stopPort>
                    <stopKey>STOP</stopKey>
                    <systemProperties>
                       <systemProperty>
                           <name>jetty.port</name>
                           <value>18080</value>
                       </systemProperty>
                    </systemProperties>
                </configuration>
                <executions>
                    <execution>
                        <id>start-jetty</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <scanIntervalSeconds>0</scanIntervalSeconds>
                            <daemon>true</daemon>
                        </configuration>
                    </execution>
                    <execution>
                        <id>stop-jetty</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

源代码


翻译自: https://www.javacodegeeks.com/2014/01/project-student-webservice-server-with-jersey.html

jersey put 服务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值