栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Apache CXF 开发 JAX-RS Restful web service - 集成 Spring 和 Hibernate

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Apache CXF 开发 JAX-RS Restful web service - 集成 Spring 和 Hibernate

什么是JAX-RS

全称Java API for RESTful Web Services,用于开发 RESTful风格的Webservice。

简介

本项目使用Apache CXF 开发RESTful风格的Web Service 服务,集成Spring和Hibernate,数据持久化到H2内存数据库。而且接口支持XML和JSON两种数据格式。

使用版本:

  • JDK 11
  • Apache CXF 3.4.5
  • Spring 5.3.13
  • jaxb2-maven-plugin 2.5.0
  • cargo-maven3-plugin 1.9.8
  • Hibernate 5.6.1
开发项目

首先,展示下项目依赖,pom文件的部分信息


        
        
            org.apache.cxf
            cxf-rt-frontend-jaxrs
        
        
            org.apache.cxf
            cxf-rt-transports-http-jetty
        

        
        
            com.fasterxml.jackson.jaxrs
            jackson-jaxrs-json-provider
            runtime
        

        
        
            org.springframework
            spring-core
        
        
            org.springframework
            spring-context
        
        
            org.springframework
            spring-web
        
        
            org.springframework
            spring-orm
        

        
        
            org.hibernate
            hibernate-core
        

        
            com.h2database
            h2
            runtime
        

        
            org.apache.httpcomponents
            httpclient
            test
        
    

因为涉及持久化,所有需要创建实体及数据访问类,创建实体(Player.java)如下:

@Entity
@Table(name = "PLAYER")
@Data
public class Player {
    @Id 
	@SequenceGenerator(name="player_sequence", allocationSize = 1)
	@GeneratedValue(strategy=GenerationType.SEQUENCE , generator="player_sequence")
	@Column(name = "PLAYER_ID")
	private int playerId;

	@Column(name= "NAME")
	private String name;

	@Column(name= "AGE")
	private int age;

	@Column(name= "MATCHES")
	private int matches;

	// 其他方法省略

 实体主键使用序列,规定了序列的名字,后面测试脚本使用了这个序列。 为了方便,省略了数据访问类,直接使用 SessionFactory 访问数据。

下面是Web Services 接口(PlayerService.java)代码:

@Path("/players")
public interface PlayerService {
    @POST
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	@Produces({MediaType.TEXT_PLAIN})
	public Response create(PlayerType playerType);

	@GET
	@Path("/{id}")
	@Consumes({MediaType.APPLICATION_FORM_URLENCODED})
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Response getById(@PathParam("id") int id);

	@PUT
	@Path("/{id}")
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_FORM_URLENCODED})
	public Response update(@PathParam("id") int id, PlayerType playerType);

	@DELETE
	@Path("/{id}")
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON,})
	@Produces({MediaType.APPLICATION_FORM_URLENCODED})
	public Response delete(@PathParam("id") int id);

	@GET
	@Consumes({MediaType.APPLICATION_FORM_URLENCODED})
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Response getByName(@QueryParam("name") String name);   
}

我们的接口支持XML和JSON,这个功能是需要配置的。在实现接口之前,我们需要定义客户端的视图类,也就接口返回的实体。当然,我们可以使用领域模型(Player)类,但不建议这样做。

创建客户端视图类,最好的做法是自动生成,我们编写xsd文件,使用jaxb2-maven-plugin创建自动生成文件,接口有变化时,修改xsd文件即可。创建xsd文件(Player.xsd):





    
    
        
            
                
                
                
                
            
        
    

    
    
        
            
                
            
        
    

在pom中定义插件

        
            
            
            
            
                org.codehaus.mojo
                jaxb2-maven-plugin
                
                    
                        
                            xjc
                        
                        generate-sources
                    
                
                
                    
                    io.github.kavahub.learnjava

                    
                        ${basedir}/src/main/resources/xsd
                    

                    en
                
            
        

在命令行运行命令:

mvn generate-sources

成功后,自动生成的文件在target/generated-sources/jaxb 下。我们需要将这个目录添加到classpath路径中,因为Web Services接口实现类需要。在pom中配置如下:

        
            
                target/generated-sources/jaxb
            
        

配置完成后,保存pom文件,路径自动添加到classpath中。每次使用Maven构建项目时,自动生成代码会删除并重新生成,与xsd文件保持一致。

完成上面步骤,我们可以实现Web Services接口(PlayerServiceImpl.java):

@Service("playerService")
public class PlayerServiceImpl implements PlayerService {
    private final SessionFactory sessionFactory;

    public PlayerServiceImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Transactional
    @Override
    public Response create(PlayerType playerType) {

        // 创建需要保存的实体
        Player playerForCreate = new Player();
        // 转换
        playerForCreate.setName(playerType.getName());
        playerForCreate.setAge(playerType.getAge());
        playerForCreate.setMatches(playerType.getMatches());

        // 持久化,返回主键
        int playerId = (Integer) sessionFactory.getCurrentSession().save(playerForCreate);
        return Response.status(Status.CREATED).entity(playerId).build();
    }


    @Transactional
    @Override
    public Response getById(int id) {

        Player player = this.findById(id);
        if (player == null) {
            return Response.status(Status.NOT_FOUND).build();
        }

        // 传话
        PlayerType getplayer = new PlayerType();
        getplayer.setPlayerId(player.getPlayerId());
        getplayer.setName(player.getName());
        getplayer.setAge(player.getAge());
        getplayer.setMatches(player.getMatches());
        return Response.ok(getplayer).build();
    }

    
    @Transactional
    @Override
    public Response update(int id, PlayerType playerType) {

        Player playerForUpdate = this.findById(id);
        if (playerForUpdate == null) {
            return Response.status(Status.NOT_FOUND).build();
        }

        playerForUpdate.setName(playerType.getName());
        playerForUpdate.setAge(playerType.getAge());
        playerForUpdate.setMatches(playerType.getMatches());

        // update database with player information and return success msg
        sessionFactory.getCurrentSession().update(playerForUpdate);
        return Response.status(Status.NO_CONTENT).build();
    }


    @Transactional
    @Override
    public Response delete(int id) {
        Player playerForDelete = this.findById(id);
        if (playerForDelete == null) {
            return Response.status(Status.NOT_FOUND).build();
        }

        sessionFactory.getCurrentSession().delete(playerForDelete);
        return Response.status(Status.NO_CONTENT).build();
    }



    @Transactional
    @Override
    public Response getByName(String name) {

        // 创建查询对象
        Query query = sessionFactory.getCurrentSession().createQuery("from Player where name like :name", Player.class);
        query.setParameter("name", "%" + name + "%");
        List lstPlayer = query.list();
        
        // 转换
        PlayerListType playerListType = new PlayerListType();
        for (Player player : lstPlayer) {
            PlayerType playerType = new PlayerType();
            playerType.setPlayerId(player.getPlayerId());
            playerType.setName(player.getName());
            playerType.setAge(player.getAge());
            playerType.setMatches(player.getMatches());
            playerListType.getPlayerType().add(playerType);
        }
        return Response.ok(playerListType).build();
    }

    private Player findById(int id) {
        
        return sessionFactory.getCurrentSession().get(Player.class, id);
    }
}

Java代码开发完成了,还没有完成,继续。我们需要些配置接口,转换器等,如下(apache-cxf-services.xml):




	
	

	
	

	
	
		
			
		

		
			 
			   
		

		
			
			
		
	

接下来,配置Spring,如下(applicationContext.xml):




	
	

	
	

	
	

	
	
		
	

	
	
		
		
			
				io.github.kavahub.learnjava.Player
			
		
		
			
				org.hibernate.dialect.H2Dialect
				update
				true
			
		
	


	
	
		
		
		
		
		

	
		
	 

最后是配置web上下文,如下(web.xml):



    Apache CXF: JAX-RS Restful web service  Integrating with Spring And Hibernate
    
        Apache CXF Endpoint
        CXFServlet
        CXFServlet
        org.apache.cxf.transport.servlet.CXFServlet
        1
    
    
        CXFServlet
        /services/*
    

    	
	
		contextConfigLocation
		
			WEB-INF/apache-cxf-services.xml,
			WEB-INF/applicationContext.xml
		
	

	
	
		org.springframework.web.context.ContextLoaderListener
	

    
        60
    

程序已经开发完成了,可以打包运行了,使用Maven打包:

mvn clean install

在target目录下,生成war包,部署到tomcat容器即可。

 调试

部署启动成功后,可以调试程序。在游览器中安装restclient插件Boomerang - SOAP & REST Client ,导入项目下的apache-cxf-spring-hibernate_boomerang.json文件。我们可以在游览器中调用接口了

请求主页

getById 接口 放回xml数据

getById 接口 放回json数据

 create接口

update接口

getByName接口

 delete接口

 集成测试

运行Maven命令执行集成测试:

mvn clean install -Pintegration-test

 测试执行过程是:启动内嵌Tomcat服务,部署项目到Tomcat,执行测试用例,关闭Tomcat服务。看起来很容易,其实有很多工作需要完成。首先我们需要配置cargo-maven3-plugin插件,在pom文件中配置,如下:

    
        
            integration-test
            
                
                    
                        org.codehaus.cargo
                        cargo-maven3-plugin
                        
                            
                                tomcat9x
                            

                            
                                
                                    localhost
                                    9080
                                
                            
                        
                        
                            
                                start-server
                                pre-integration-test
                                
                                    start
                                
                            
                            
                                stop-server
                                post-integration-test
                                
                                    stop
                                
                            
                        
                    
                
            
        
    

配置使用tomcat 9的版本,端口是9080

其次,我们需要编写测试用例(PlayerIntegrationTest.java),如下:

public class PlayerIntegrationTest {
    private static final String base_URL = "http://localhost:9080/apache-cxf-spring-hibernate/services/players/";
    private static CloseableHttpClient client;

    @BeforeAll
    public static void createClient() {
        client = HttpClients.createDefault();
    }

    @AfterAll
    public static void closeClient() throws IOException {
        client.close();
    }

    @Test
    public void givenPlayId_whenGet_thenReturenPlayer() throws IOException {
        final int playerId = 1;

        final HttpGet httpGet = new HttpGet(base_URL + playerId);
        final HttpResponse response = client.execute(httpGet);

        assertEquals(200, response.getStatusLine().getStatusCode());

        final PlayerType player = JAXB.unmarshal(new InputStreamReader(response.getEntity().getContent()),
                PlayerType.class);
        assertEquals("Sachin Tendulkar", player.getName());
    }

    @Test
    public void givenPlayId_whenGet_thenNotFound() throws IOException {
        final int playerId = 0;

        final HttpGet httpGet = new HttpGet(base_URL + playerId);
        final HttpResponse response = client.execute(httpGet);

        assertEquals(404, response.getStatusLine().getStatusCode());
    }

    @Test
    public void givenPlayId_whenDelete_thenOk() throws IOException {
        final int playerId = 2;

        final HttpDelete httpDelete = new HttpDelete(base_URL + playerId);
        final HttpResponse response = client.execute(httpDelete);

        assertEquals(204, response.getStatusLine().getStatusCode());
    }

    @Test
    public void givenPlayId_whenDelete_thenNotFound() throws IOException {
        final int playerId = 0;

        final HttpDelete httpDelete = new HttpDelete(base_URL + playerId);
        final HttpResponse response = client.execute(httpDelete);

        assertEquals(404, response.getStatusLine().getStatusCode());
    }

    @Test
    public void givenPlayerType_whenPut_thenOk() throws IOException {
        final int playerId = 3;

        final HttpPut httpPut = new HttpPut(base_URL + playerId);
        httpPut.setHeader("Content-Type", "application/xml");
        
        final Path xmlFile = Paths.get("src", "test", "resources", "changed_player.xml");
        httpPut.setEntity(new StringEntity(Files.readString(xmlFile), "UTF-8"));
        final HttpResponse response = client.execute(httpPut);

        assertEquals(204, response.getStatusLine().getStatusCode());

        PlayerType player = getPlayer(playerId);
        assertNotNull(player);
        assertEquals("李四", player.getName());
    }

    @Test
    public void givenPlayerType_whenPut_thenNotFound() throws IOException {
        final int playerId = 0;

        final HttpPut httpPut = new HttpPut(base_URL + playerId);
        httpPut.setHeader("Content-Type", "application/xml");
        
        final Path xmlFile = Paths.get("src", "test", "resources", "changed_player.xml");
        httpPut.setEntity(new StringEntity(Files.readString(xmlFile), "UTF-8"));
        final HttpResponse response = client.execute(httpPut);

        assertEquals(404, response.getStatusLine().getStatusCode());
    }

    @Test
    public void givenPlayerType_whenPost_thenNotFound() throws IOException {
        final HttpPost httpPost = new HttpPost(base_URL);
        httpPost.setHeader("Content-Type", "application/xml");
        
        final Path xmlFile = Paths.get("src", "test", "resources", "create_player.xml");
        httpPost.setEntity(new StringEntity(Files.readString(xmlFile), "UTF-8"));
        final HttpResponse response = client.execute(httpPost);

        assertEquals(201, response.getStatusLine().getStatusCode());

        final int playerId = Integer.parseInt(EntityUtils.toString(response.getEntity()));
        final PlayerType player = getPlayer(playerId);
        assertEquals("王五", player.getName());
    }

    private PlayerType getPlayer(int playerId) throws IOException {
        final URL url = new URL(base_URL + playerId);
        final InputStream input = url.openStream();
        return JAXB.unmarshal(new InputStreamReader(input), PlayerType.class);
    }
}

测试使用HttpClient工具

到这里,全部完成了,恭喜!!!!

最后

访问源代码库,获取全部代码apache-cxf-spring-hibernate

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/644249.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号