SpringBoot整合CXF,實現Restful api 與 WebService api dao層使用Mybatis
1、本demo目的查詢學生資訊【為了方便沒有寫批量查詢,也就是說以下getAllStudents也是一個一個查詢【而且沒有測試該方法正確性,之所以寫只是為了規範,返回Student的集合Students也是一個獨立的實體,非必需,請忽略】
2、主要是網上好多不全,整合的時候各種坑,我就記錄一下。
一、老規矩,先搞個數據庫
命名demo【可自己修改】ps【忽略細節,只是為了說明問題】/* Navicat MySQL Data Transfer Source Server : root Source Server Version : 50540 Source Host : localhost:3306 Source Database : demo Target Server Type : MYSQL Target Server Version : 50540 File Encoding : 65001 Date: 2018-03-23 16:21:20 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `student` -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(10) NOT NULL, `name` varchar(100) DEFAULT NULL, `sex` char(6) DEFAULT NULL, `address` varchar(255) DEFAULT NULL, `age` int(10) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('1', '李斯', '男', '江西南昌', '22');
二、maven依賴【可能不是最少依賴】
<?xml version="1.0" encoding="UTF-8"?> <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"> <modelVersion>4.0.0</modelVersion> <groupId>cn.edu.jxnu</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.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> </properties> <dependencies> <!-- 提供JacksonJsonProvider,非必需,學過jersey,所以在這塊直接使用了,可以使用其他json轉化替換,使用cxf的有很多問題,沒法填 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxrs</artifactId> <version>3.1.11</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.1.6</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>3.1.6</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>3.1.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
三、實體類
學生集合實體package cn.edu.jxnu.entity; import java.io.Serializable; import javax.xml.bind.annotation.XmlRootElement; /** * 學生實體類 * * @author: liguobin * @Description: * @時間: 2018-3-7 下午3:42:04 * @version: V1.0 * */ @XmlRootElement(name = "Student") public class Student implements Serializable { private static final long serialVersionUID = 1L; private Integer id; private String name; private char sex; private String address; private Integer age; public Student() { super(); } public Student(Integer id, String name, char sex, String address, Integer age) { super(); this.id = id; this.name = name; this.sex = sex; this.address = address; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", address=" + address + ", age=" + age + "]"; } }
package cn.edu.jxnu.entity;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* 封裝多個學生實體類
*
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:42:14
* @version: V1.0
*
*/
@XmlRootElement(name = "Students")
public class Students {
private List<Student> students;
public Students(List<Student> students) {
super();
this.students = students;
}
@XmlElement(name = "Student")
public List<Student> getStudents() {
return students;
}
public Students() {
super();
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
四、開始整合SpringBoot mybatis
整合myabtis的具體不再贅述,網上很多也很簡單。application.properties#server port set
server.port: 8082
#mysql datasource set
spring.datasource.
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.typeAliasesPackage=cn.edu.jxnu.entity
mybatis.mapperLocations=classpath\:mapper/*.xml
mybatis.config-location=classpath\:mybatis-config.xml
spring.jackson.serialization.indent_output =true
logging.level.org.springframework.web=WARN
#logging.file = C\:\\web\\temp\\log\\log.log
logging.level.org.springframework=WARN
logging.level.cn.edu.jxnu.dao=INFO
logging.level.cn.edu.jxnu.resource=WARN
mybatis-config.xml 【沒幹什麼】
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 在這裡僅僅為了開啟懶載入 -->
<settings>
<!-- 開啟延遲載入的開關 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 將積極載入改為消極載入,即延遲載入 -->
<setting name="aggressiveLazyLoading" value="false" />
<setting name="cacheEnabled" value="true" />
</settings>
</configuration>
StudentMapper.xml mapper檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.jxnu.dao.StudentDao">
<resultMap type="cn.edu.jxnu.entity.Student" id="Student">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="address" column="address" />
<result property="age" column="age" />
</resultMap>
<!-- 定義欄位集合 -->
<sql id="studentInformation">
id,name,sex,address,age
</sql>
<select id="getStudentById" resultMap="Student" flushCache="true"
parameterType="java.lang.Integer">
select
<include refid="studentInformation" />
from student where id=#{id}
</select>
<!-- 重新整理間隔 -->
<cache flushInterval="600000" />
</mapper>
mapper介面
package cn.edu.jxnu.dao;
import org.apache.ibatis.annotations.Param;
import cn.edu.jxnu.entity.Student;
/**
* dao層資料操作介面
*
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:41:43
* @version: V1.0
*
*/
public interface StudentDao {
Student getStudentById(@Param("id") Integer id);
}
配置SpringBoot掃描dao【這個也是主啟動類,學過SpringBoot應該都知道,不再贅述】
package cn.edu.jxnu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Controller;
/**
* 啟動類
*
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:41:24
* @version: V1.0
*
*/
@Controller
@MapperScan("cn.edu.jxnu.dao")
@SpringBootApplication
// / 沒有這個rest失效 只存在soap
@ImportResource(locations = { "classpath:cxf-config.xml" })
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
cxf-config.xml很重要,等等再說
五、重點 整合cxf webService【注意,不是restful,而是webservice 基於soap的】
cxf配置類【因為是使用SpringBoot,所以使用類和註解配置】
package cn.edu.jxnu; import javax.xml.ws.Endpoint; import org.apache.cxf.Bus; import org.apache.cxf.bus.spring.SpringBus; import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.transport.servlet.CXFServlet; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import cn.edu.jxnu.serviceImpl.StudentServiceImpl; /** * * @author: liguobin @Description: @時間: 2018-3-7 下午4:11:57 @version: V1.0 * */ @Configuration public class CxfConfig { @Bean public ServletRegistrationBean newServlet() { return new ServletRegistrationBean(new CXFServlet(), "/cxf/*"); } @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { return new SpringBus(); } /** * @return */ @Bean @Qualifier("studentServiceImpl") // 注入webService public Endpoint endpoint(StudentRestfulServiceImpl studentServiceImpl) { EndpointImpl endpoint = new EndpointImpl(springBus(), studentServiceImpl); endpoint.publish("/webService");// 暴露webService api,用在資源訪問 return endpoint; } @Bean("jsonProvider") // 構造一個json轉化bean,用於將student轉化為json,因為後面需要用這個bean配置json轉化,所以給他取個名 public JacksonJsonProvider getJacksonJsonProvider() { return new JacksonJsonProvider(); } }
CXFServlet()是返回一個cxf Servlet,用來攔截cxf,這裡傳入攔截路徑/cxf/* 也就是訪問路徑是: ip:port/cxf/這裡填@path的值
此處為了說明我寫了一個Spring Controllerpackage cn.edu.jxnu;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.edu.jxnu.entity.Student;
import cn.edu.jxnu.entity.Students;
import cn.edu.jxnu.service.StudentService;
import com.alibaba.fastjson.JSONObject;
/**
* Spring 前端控制
*
* 通過這個返回正確,作對比
*
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:35:17
* @version: V1.0
*
*/
@Controller
public class SpringController {
@Autowired
private StudentService studentService;
@ResponseBody
@Produces({ MediaType.APPLICATION_JSON + "charset='utf-8'" })
@RequestMapping(value = "get/{id}", method = RequestMethod.GET)
public String getStudent(@PathVariable("id") Integer id) {
Student student = studentService.getStudent(id);
Object json = JSONObject.toJSON(student);
return json.toString();
}
/**
* @引數:{"ids":{"id":[1,2,3,4]
*
* @param ids
* @return
*/
@ResponseBody
@Produces({ MediaType.APPLICATION_JSON + "charset='utf-8'" })
@Consumes({ MediaType.APPLICATION_JSON })
@RequestMapping(value = "gets/{ids}", method = RequestMethod.GET)
public String getAll(@PathVariable("ids") String ids) {
Students students = studentService.getAllStudent(ids);
Object json = JSONObject.toJSON(students);
return json.toString();
}
}
眾所周知springmvc的預設由dispatherServlet處理。所以這裡使用ip:port/get/1 即可獲取【@PathVariable 是Spring的 與PathParam 是JSR-RS的功能類似】
此處只是為了說明cxf 的重要性。可以看到,沒有使用/cxf/ 就依然是由springmvc來處理的
編寫webservice 介面 基本是最簡了
package cn.edu.jxnu.service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import cn.edu.jxnu.entity.Student;
import cn.edu.jxnu.entity.Students;
/**
* @description WebService介面定義 soap
* @author liguobin
*
*/
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) // 返回型別
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) // 請求型別
@WebService
public interface StudentService {
/**
* 查詢一個學生
*
* @param id
* @return
*/
@WebMethod
public Student getStudent(@WebParam(name = "id") Integer id);
/**
* 查詢多個學生
*
* @param ids
* @return
*/
@WebMethod
public Students getAllStudent(@WebParam(name = "ids") String ids);
}
實現service
package cn.edu.jxnu.serviceImpl;
import java.util.ArrayList;
import javax.jws.WebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.edu.jxnu.dao.StudentDao;
import cn.edu.jxnu.entity.Student;
import cn.edu.jxnu.entity.Students;
import cn.edu.jxnu.service.StudentService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* 實現webservice介面,對外暴露 soap
*
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:43:06
* @version: V1.0
*
*/
@Component//由Spring管理
@WebService(endpointInterface = "cn.edu.jxnu.service.StudentService") // webservice介面的全類名
public class StudentServiceImpl implements StudentService {
/**
* 注入spring bean
*/
@Autowired
private StudentDao studentDao;
@Override
public Student getStudent(Integer id) {
return studentDao.getStudentById(id);
}
/**
* 沒有測試正確性,不是本文重點
*/
@Override
public Students getAllStudent(String ids) {
Students students = new Students(new ArrayList<Student>());
// 得到json物件
JSONObject json = JSONObject.parseObject(ids);
// 獲取物件的id列表
JSONArray sid = json.getJSONArray("id");
for (int i = 0; i < sid.size(); i++) {
Integer s = sid.getInteger(0);
if (s != null) {
students.getStudents().add(studentDao.getStudentById(s));
} else {
continue;
}
}
return students;
}
}
測試webservice
輸入http://localhost:8082/cxf 【檢視所以soap和restful api】
單獨檢視某一個soap api【http://localhost:8082/cxf/webService?wsdl】 在前文 endpoint.publish("/webService");// 就是這個webService
瀏覽器顯示:
點選wsdl
名稱空間等等都是預設的,沒有在webservice配置。也為了簡潔
六、整合Restful api【 RESTful services】
首先,編寫rest一個介面
package cn.edu.jxnu.resource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import cn.edu.jxnu.entity.Student;
import cn.edu.jxnu.entity.Students;
/**
* @author: liguobin
* @Description:
* @時間: 2018-3-7 下午3:59:15
* @version: V1.0
*
*/
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public interface StudentInterface {
/**
* @param id
* @return
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/getone/{id:[0-9]{0,10}}") // 限制id只能是0~9的陣列 不超過10位
public Student getStudent(@PathParam("id") Integer id);
/**
* 查詢多個學生
*
* @param ids
* @return
*/
@GET
@Produces({ MediaType.APPLICATION_JSON })
@Path("/getmany/{ids}")
public Students getAllStudent(@PathParam("ids") String ids);
}
實現rest介面
package cn.edu.jxnu.resource;
import java.util.ArrayList;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.edu.jxnu.entity.Student;
import cn.edu.jxnu.entity.Students;
import cn.edu.jxnu.service.StudentService;
@Path("/")
public class StudentInterfaceImpl implements StudentInterface {
@Autowired
private StudentService studentService;
// 獲取json
@Override
@GET
@Path("/getjson/{id:[0-9]{0,10}}")
@Produces({ MediaType.APPLICATION_JSON })
public Student getStudent(@PathParam("id") Integer id) {
return studentService.getStudent(id);
}
// 獲取xml
@GET
@Path("/getxml/{id}")
@Produces({ MediaType.APPLICATION_XML })
public Student getStudent2(@PathParam("id") Integer id) {
return studentService.getStudent(id);
}
/**
* 返回students集合,此方法沒有測試,引數是一個json物件,該物件包含一個name為id的陣列
*/
@Override
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/getmany/{ids}")
public Students getAllStudent(@PathParam("ids") String ids) {
Students students = new Students(new ArrayList<Student>());
// 得到json物件
JSONObject json = JSONObject.parseObject(ids);
// 獲取物件的id列表
JSONArray sid = json.getJSONArray("id");
for (int i = 0; i < sid.size(); i++) {
Integer s = sid.getInteger(0);
if (s != null) {
students.getStudents().add(studentService.getStudent(s));
} else {
continue;
}
}
return students;
}
}
寫法不標準甚至有錯不要在意,不是本文重點rest介面和類都寫完,剩下就是配置了
前文,在主類曾經匯入過一個配置檔案,這個檔案就是專門用來配置cxf的【@ImportResource(locations = { "classpath:cxf-config.xml" })】
cxf-config.xml
<?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:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 將Bean託管給Spring -->
<bean id="studentService" class="cn.edu.jxnu.resource.StudentInterfaceImpl">
</bean>
<!-- 配置需要暴露的Rest ful Service -->
<jaxrs:server id="restContainer" address="/students"> <!-- 暴露restful api 類似於前文提到的webService【暴露soap】 即訪問的時候要加上這個address -->
<jaxrs:serviceBeans>
<!-- 相當於打包釋出服務 -->
<ref bean="studentService" />
</jaxrs:serviceBeans>
<!-- 提供一個json轉化,沒有這個不能自動返回json jsonProvider就是前面@Bean生成的在CxfConfig -->
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
</beans>
檢視RestFul api
瀏覽器輸入http://localhost:8082/cxf/ 就可以檢視到多了 Available RESTful services:Endpoint address: http://localhost:8082/cxf/students
【因為soap和restful均是cxf處理】
最後測試restful請求
輸入http://localhost:8082/cxf/students/getjson/1 獲取json資料
輸入http://localhost:8082/cxf/students/getxml/1 獲取xml資料
github 原始碼:https://github.com/jxnu-liguobin/SpringBoot-CXF-demo
以上僅供參考