Windchill开发-WindchillREST
- 创业
- 2025-08-24 06:09:01

Windchill REST 一、作用二、定义RESTful接口2.1 接口通用类2.1.1 接口基础返回信息相关类2.1.2 HTTP通信返回信息相关类2.1.3 接口通用入参类2.1.3.1 用户名2.1.3.1 来源系统 2.2 接口专用类2.2.1 接口专用返回信息类2.2.1.1 部件信息2.2.1.2 部件信息实现2.2.1.3 部件查询集成返回信息2.2.1.4 部件查询集成返回信息实现 2.2.2 接口专用入参类2.2.2.1 部件查询集成入参2.2.2.2 部件查询集成入参实现 2.2.3 接口配置文件2.2.4 接口配置文件读取类2.2.5 接口主逻辑及实现类2.2.5.1 测试接口服务2.2.5.2 测试接口服务实现2.2.5.3 测试接口REST服务2.2.5.4 测试接口REST服务实现2.2.5.5 测试接口REST服务封装 2.3 注册REST服务 三、注解说明四、接口调试4.1 swagger调试4.1.1 获取Token 4.2 第三方工具调试4.3 测试类调试4.3.1 HttpURLConnection调用工具类4.3.2 用户登陆(GET)接口调试4.3.3 查询部件信息(POST)接口调试 一、作用
REST(Representational State Transfer,表述性状态转移) 是一种软件架构风格。REST提出了一组架构约束条件和原则,任何满足 REST 约束条件和原则的架构,都称为 RESTful 架构。RESTful 用于替代Webservice,实现系统间的集成。无需生成客户端代码,直接使用HTTP方式进行系统间的通讯。
二、定义RESTful接口 2.1 接口通用类 2.1.1 接口基础返回信息相关类 package xxx.xxx.integration.rest.bean; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "BaseReturnObject", description = "基础接口返回对象") public interface BaseReturnObject { @XmlElement @ApiModelProperty(value = "操作者", example = "wcadmin", required = true, position = 10) String getOperator(); @XmlElement @ApiModelProperty(value = "返回状态,成功或失败", example = "success", required = true, position = 20) String getStatus(); @XmlElement @ApiModelProperty(value = "返回信息,一般是失败时返回", example = "调用失败:xxx", required = true, position = 30) String getMessage(); } package xxx.xxx.integration.rest.bean; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; @XStreamAlias("BaseReturnObjectImpl") public class BaseReturnObjectImpl implements BaseReturnObject { @XStreamAsAttribute private String operator; @XStreamAsAttribute private String status; @XStreamAsAttribute private String message; /** * 实例化 * * @param operator 操作者 * @param status 返回状态 * @param message 返回信息 * @return */ public static BaseReturnObjectImpl newInstance(String operator, String status, String message) { BaseReturnObjectImpl impl = new BaseReturnObjectImpl(); impl.setOperator(operator); impl.setStatus(status); impl.setMessage(message); return impl; } @Override public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } @Override public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }如果需要实现文件传输,则需要一个专门处理文件流的类:
package xxx.xxx.integration.rest.bean; import org.apache.xmlbeans.impl mon.IOUtil; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.StreamingOutput; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class ApplicationDataFileOutput implements StreamingOutput { private InputStream inputStream; private String mimeType; private String fileName; public ApplicationDataFileOutput(InputStream inputStream, String mimeType, String fileName) { this.inputStream = inputStream; this.mimeType = mimeType; this.fileName = fileName; } @Override public void write(OutputStream outPutStream) throws IOException, WebApplicationException { IOUtil.copyCompletely(inputStream, outPutStream); } public String getMimeType() { return mimeType; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public InputStream getInputStream() { return inputStream; } } 2.1.2 HTTP通信返回信息相关类 package xxx.xxx.integration.rest.base; public interface RestResourceAware { BaseRestResource<?> getRestResource(); void setRestResource(BaseRestResource resource); } package xxx.xxx.integration.rest.base; import xxx.xxx.integration.rest.bean.BaseReturnObject; import xxx.xxx.integration.rest.bean.BaseReturnObjectImpl; import com.ptc.windchill.rest.utility.error.RestMessage; import org.springframework.web.servlet.support.RequestContextUtils; import wt.session.SessionHelper; import wt.util.WTException; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import java.util.Locale; public class BaseRestResourceAware implements RestResourceAware { public static final String STATUS_SUCCESS = "SUCCESS"; public static final String STATUS_FAILURE = "FAILURE"; protected BaseRestResource<?> restResource; @Override public BaseRestResource<?> getRestResource() { return restResource; } @Override public void setRestResource(BaseRestResource resource) { this.restResource = resource; } public Response buildErrorResponse(int httpCode, String erroCode, String errorMessage) { RestMessage message = new RestMessage(); message.setCode(erroCode); message.setText(errorMessage); ResponseBuilder responseBuilder = Response.status(httpCode).entity(message); return responseBuilder.build(); } public Response buildExceptionResponse(String errorMessage) { BaseReturnObject result = null; try { result = BaseReturnObjectImpl.newInstance(SessionHelper.getPrincipal().getName(), STATUS_FAILURE, errorMessage); } catch (WTException e) { result = BaseReturnObjectImpl.newInstance("Adminstrator", STATUS_FAILURE, errorMessage); } ResponseBuilder responseBuilder = Response.status(200).entity(result); return responseBuilder.build(); } public Response buildEntityResponse(int httpCode, Object entity) { ResponseBuilder responseBuilder = Response.status(httpCode).entity(entity); return responseBuilder.build(); } public Response buildSuccessResponse(int httpCode, String successCode, String successMessage) { RestMessage message = new RestMessage(); message.setCode(successCode); message.setText(successMessage); ResponseBuilder responseBuilder = Response.status(httpCode).entity(message); return responseBuilder.build(); } /** * 获取header中的用户名并设置到session * * @return */ public boolean setUserFromHeader(String userName) { boolean setted = false; if (userName != null && !userName.isEmpty()) { try { SessionHelper.manager.setPrincipal(userName); setted = true; } catch (WTException e) { setted = false; } } return setted; } public Locale getLocale() { Locale locale = RequestContextUtils.getLocale(this.getRestResource().getHttpServletRequest()); return locale; } } package xxx.xxx.integration.rest.base; import com.ptc.core.rest.AbstractResource; import com.ptc.xworks.util.ObjectUtils; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Request; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; public abstract class BaseRestResource<ServiceImpl extends RestResourceAware> extends AbstractResource { @Context protected UriInfo uriInfo; @Context protected Request request; @Context protected HttpServletRequest servletRequest; @Context protected HttpServletResponse servletResponse; @Context protected ServletConfig servletConfig; public UriInfo getUriInfo() { return uriInfo; } public Request getRequest() { return request; } public HttpServletRequest getHttpServletRequest() { return servletRequest; } public HttpServletResponse getHttpServletResponse() { return servletResponse; } public ServletConfig getServletConfig() { return servletConfig; } public SecurityContext getSecurityContext() { return this.securityContext; } public ServletContext getServletContext() { return this.servletContext; } public HttpHeaders getHttpHeaders() { return this.httpHeaders; } public abstract Class<ServiceImpl> getServiceImplClass(); public ServiceImpl getServiceImpl() { ServiceImpl serviceImpl = ObjectUtils.createNewInstance(this.getServiceImplClass()); serviceImpl.setRestResource(this); return serviceImpl; } } 2.1.3 接口通用入参类 2.1.3.1 用户名 package xxx.xxx.integration.rest.param; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "UsernameParam", description = "每次请求带的用户名信息") public interface UsernameParam { @XmlElement @ApiModelProperty(value = "用户名", example = "wcadmin", required = true, position = 10) String getUsername(); } 2.1.3.1 来源系统 package xxx.xxx.integration.rest.param; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "TargetSystemParam", description = "每次请求带的调用系统标识信息") public interface TargetSystemParam { @XmlElement @ApiModelProperty(value = "调用系统", example = "OA", required = true, position = 10) String getResource(); } 2.2 接口专用类以用户登陆(GET)和部件信息查询(POST)接口为例:
2.2.1 接口专用返回信息类 2.2.1.1 部件信息 package xxx.xxx.integration.rest.test.bean; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "PartInfo", description = "部件信息") public interface PartInfo { @XmlElement @ApiModelProperty(value = "部件名称", example = "显示器", required = false, position = 10) String getPartName(); @XmlElement @ApiModelProperty(value = "状态", example = "已发布", required = false, position = 10) String getLifeCycleState(); @XmlElement @ApiModelProperty(value = "创建者", example = "张三", required = false, position = 10) String getCreator(); @XmlElement @ApiModelProperty(value = "默认单位", example = "台", required = false, position = 10) String getUnit(); } 2.2.1.2 部件信息实现 package xxx.xxx.integration.rest.test.bean; import wt.part.WTPart; import wt.util.WTException; public class PartInfoImpl implements PartInfo { private String partName; private String lifeCycleState; private String creator; private String unit; public static PartInfo newPartInfo(WTPart part) throws WTException { PartInfoImpl impl = new PartInfoImpl(); if (part != null) { impl.setPartName(part.getName()); impl.setLifeCycleState(part.getLifeCycleState().getDisplay()); impl.setCreator(part.getCreatorFullName()); impl.setUnit(part.getMaster().getDefaultUnit().getDisplay()); } return impl; } @Override public String getPartName() { return partName; } public void setPartName(String partName) { this.partName = partName; } @Override public String getLifeCycleState() { return lifeCycleState; } public void setLifeCycleState(String lifeCycleState) { this.lifeCycleState = lifeCycleState; } @Override public String getCreator() { return creator; } public void setCreator(String creator) { this.creator = creator; } @Override public String getUnit() { return unit; } public void setUnit(String unit) { this.unit = unit; } } 2.2.1.3 部件查询集成返回信息 package xxx.xxx.integration.rest.test.bean; import xxx.xxx.integration.rest.bean.BaseReturnObject; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "PartReturnObject", description = "部件查询集成返回结果信息") public interface PartReturnObject extends BaseReturnObject { @XmlElement @ApiModelProperty(value = "部件信息", example = "", required = false, position = 10) PartInfo getPartInfo(); } 2.2.1.4 部件查询集成返回信息实现 package xxx.xxx.integration.rest.test.bean; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; public class PartReturnObjectImpl implements PartReturnObject { @XStreamAsAttribute private String operator; @XStreamAsAttribute private String status; @XStreamAsAttribute private String message; @XStreamAsAttribute private PartInfo partInfo; public static PartReturnObject newPartReturnObject(String operator, String status, String message, PartInfo partInfo) { PartReturnObjectImpl impl = new PartReturnObjectImpl(); impl.setOperator(operator); impl.setStatus(status); impl.setMessage(message); impl.setPartInfo(partInfo); return impl; } @Override public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } @Override public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public PartInfo getPartInfo() { return partInfo; } public void setPartInfo(PartInfo partInfo) { this.partInfo = partInfo; } } 2.2.2 接口专用入参类 2.2.2.1 部件查询集成入参 package xxx.xxx.integration.rest.test.param; import xxx.xxx.integration.rest.param.TargetSystemParam; import xxx.xxx.integration.rest.param.UsernameParam; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() @ApiModel(value = "QueryPartParam", description = "用于查询部件的参数") public interface QueryPartParam extends UsernameParam, TargetSystemParam { @XmlElement @ApiModelProperty(value = "部件编码", example = "2000012300", required = true, position = 10) String getPartNumber(); }@ApiModelProperty注解中参数position用于排序,参数allowableValues用于入参的合法值校验;
2.2.2.2 部件查询集成入参实现 package xxx.xxx.integration.rest.test.param; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; public class QueryPartParamImpl implements QueryPartParam { private String username; private String resource; private String partNumber; @JsonCreator public QueryPartParamImpl(@JsonProperty("username") String username, @JsonProperty("resource") String resource, @JsonProperty("partNumber") String partNumber) { this.username = username; this.resource = resource; this.partNumber = partNumber; } @Override public String getResource() { return resource; } public void setResource(String resource) { this.resource = resource; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String getPartNumber() { return partNumber; } public void setPartNumber(String partNumber) { this.partNumber = partNumber; } } 2.2.3 接口配置文件TestIntegrationConfiguratorRest-configs.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http:// .w3.org/2001/XMLSchema-instance" xmlns="http:// .springframework.org/schema/beans" xsi:schemaLocation="http:// .springframework.org/schema/beans http:// .springframework.org/schema/beans/spring-beans.xsd"> <bean id="testIntegrationServiceImpl" class="xxx.xxx.integration.rest.test.service.TestIntegrationServiceImpl" scope="prototype"> </bean> <bean id="testIntegrationRestServiceImpl" class="xxx.xxx.integration.rest.test.service.TestIntegrationRestServiceImpl" scope="prototype"> <property name="service" ref="testIntegrationServiceImpl" /> </bean> </beans>说明:该配置文件需要部署至应用服务器codebase目录下,一般情况会在对应的项目包下,路径会在接口配置文件读取类中引用。
2.2.4 接口配置文件读取类 package xxx.xxx.integration.rest.test.util; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestIntegrationApplicationContextUtils { private static final ClassPathXmlApplicationContext context; static { context = new ClassPathXmlApplicationContext("xxx/xxx/integration/rest/test/config/TestIntegrationConfiguratorRest-configs.xml"); } /** * 根据名称获得一个Spring容器中的bean的实例 * * @param beanName bean名 * @param <T> * @return */ public static <T> T getBean(String beanName) { return (T) context.getBean(beanName); } } 2.2.5 接口主逻辑及实现类 2.2.5.1 测试接口服务 package xxx.xxx.integration.rest.test.service; import xxx.xxx.integration.rest.bean.BaseReturnObject; import xxx.xxx.integration.rest.test.param.QueryPartParamImpl; import wt.util.WTException; public interface TestIntegrationService { /** * 查询部件信息 * * @param param 入参 * @return * @throws WTException */ BaseReturnObject queryPartInfo(QueryPartParamImpl param) throws WTException; /** * 用户登陆 * * @param username 用户名 * @param password 密码 * @return * @throws WTException */ BaseReturnObject userLogin(String username, String password) throws WTException; } 2.2.5.2 测试接口服务实现关于LDAP URL的获取,请参考用户登陆验证的API
package xxx.xxx.integration.rest.test.service; import xxx.xxx.integration.rest.base.BaseRestResourceAware; import xxx.xxx.integration.rest.bean.BaseReturnObject; import xxx.xxx.integration.rest.bean.BaseReturnObjectImpl; import xxx.xxx.integration.rest.test.bean.PartInfo; import xxx.xxx.integration.rest.test.bean.PartInfoImpl; import xxx.xxx.integration.rest.test.bean.PartReturnObject; import xxx.xxx.integration.rest.test.bean.PartReturnObjectImpl; import xxx.xxx.integration.rest.test.param.QueryPartParamImpl; import org.springframework.util.StringUtils; import wt.fc.PersistenceHelper; import wt.fc.QueryResult; import wt.part.WTPart; import wt.query.QuerySpec; import wt.query.SearchCondition; import wt.util.WTException; import wt.vc.config.LatestConfigSpec; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; import java.util.Hashtable; public class TestIntegrationServiceImpl implements TestIntegrationService { @Override public BaseReturnObject queryPartInfo(QueryPartParamImpl param) throws WTException { String partNumber = param.getPartNumber(); WTPart part = findWTPart(partNumber); if (part != null) { PartInfo partInfo = PartInfoImpl.newPartInfo(part); PartReturnObject object = PartReturnObjectImpl.newPartReturnObject(param.getUsername(), BaseRestResourceAware.STATUS_SUCCESS, null, partInfo); return object; } else { return BaseReturnObjectImpl.newInstance(param.getUsername(), BaseRestResourceAware.STATUS_FAILURE, "系统中未查询到部件:" + partNumber); } } @Override public BaseReturnObject userLogin(String username, String password) throws WTException { boolean flag = false; String result = ""; String status = ""; String ldapUrl = "ldap://plm.xxx "; // 实际的LDAP URL try { flag = validateLogin(username, password, ldapUrl); } catch (WTException e) { result = "登录失败,请检查用户名和密码或检查服务器状况"; status = BaseRestResourceAware.STATUS_FAILURE; } if (!StringUtils.hasText(result)) { if (flag) { result = "登陆成功"; status = BaseRestResourceAware.STATUS_SUCCESS; } else { result = "未登录,原因未知"; status = BaseRestResourceAware.STATUS_FAILURE; } } return BaseReturnObjectImpl.newInstance(username, status, result); } public static WTPart findWTPart(String partNumber) throws WTException { WTPart part = null; if (StringUtils.hasText(partNumber)) { QuerySpec queryspec = new QuerySpec(WTPart.class); SearchCondition searchCondition = new SearchCondition(WTPart.class, WTPart.NUMBER, SearchCondition.EQUAL, partNumber); queryspec.appendSearchCondition(searchCondition); QueryResult queryresult = PersistenceHelper.manager.find(queryspec); LatestConfigSpec configSpec = new LatestConfigSpec(); queryresult = configSpec.process(queryresult); if (queryresult != null && queryresult.hasMoreElements()) { part = (WTPart) queryresult.nextElement(); } } return part; } public static boolean validateLogin(String username, String password, String ldapUrl) throws WTException { Hashtable<String, String> table = new Hashtable<>(); boolean flag = false; /** * 补全用户名信息 */ username = username + ",ou=people,cn=AdministrativeLdap,cn=Windchill_11.0,o=ptc"; username = "uid=" + username; table.put(Context.PROVIDER_URL, ldapUrl); table.put(Context.SECURITY_AUTHENTICATION, "simple"); table.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); table.put(Context.SECURITY_PRINCIPAL, username); table.put(Context.SECURITY_CREDENTIALS, password); LdapContext context = null; try { context = new InitialLdapContext(table, null); } catch (NamingException e) { throw new WTException(e); } if (context != null) { flag = true; } return flag; } } 2.2.5.3 测试接口REST服务 package xxx.xxx.integration.rest.test.service; import xxx.xxx.integration.rest.test.param.QueryPartParamImpl; import javax.ws.rs.core.Response; public interface TestIntegrationRestService { /** * 查询部件信息 * * @param param 入参 * @return */ Response queryPartInfo(QueryPartParamImpl param); /** * 用户登陆 * * @param username 用户名 * @param password 密码 * @return */ Response userLogin(String username, String password); } 2.2.5.4 测试接口REST服务实现 package xxx.xxx.integration.rest.test.service; import xxx.xxx.integration.rest.base.BaseRestResourceAware; import xxx.xxx.integration.rest.bean.BaseReturnObject; import xxx.xxx.integration.rest.test.param.QueryPartParamImpl; import org.springframework.util.StringUtils; import wt.util.WTException; import javax.ws.rs.core.Response; public class TestIntegrationRestServiceImpl extends BaseRestResourceAware implements TestIntegrationRestService{ protected TestIntegrationService service; public void setService(TestIntegrationService service) { this.service = service; } @Override public Response queryPartInfo(QueryPartParamImpl param) { try { if (param == null || !StringUtils.hasText(param.getPartNumber())) { return this.buildExceptionResponse("缺失参数值!"); } /** * 设置操作的用户 */ boolean flag = this.setUserFromHeader(param.getUsername()); if (flag) { BaseReturnObject result = service.queryPartInfo(param); return this.buildEntityResponse(200, result); } else { return this.buildExceptionResponse("设置用户时发生错误,请检查用户名是否存在!"); } } catch (WTException e) { // 记录至同步记录表 return this.buildExceptionResponse("请注意,操作失败。详细异常信息请查看PLM系统日志,参考异常原因:" + e.getLocalizedMessage()); } } @Override public Response userLogin(String username, String password) { try { if (!StringUtils.hasText(username) || !StringUtils.hasText(password)) { return this.buildExceptionResponse("缺失参数值!"); } BaseReturnObject result = service.userLogin(username, password); return this.buildEntityResponse(200, result); } catch (WTException e) { return this.buildExceptionResponse("请注意,操作失败。详细异常信息请查看PLM系统日志,参考异常原因:" + e.getLocalizedMessage()); } } } 2.2.5.5 测试接口REST服务封装 package xxx.xxx.integration.rest.test.service; import xxx.xxx.integration.rest.base.BaseRestResource; import xxx.xxx.integration.rest.bean.BaseReturnObject; import xxx.xxx.integration.rest.test.param.QueryPartParamImpl; import xxx.xxx.integration.rest.test.util.TestIntegrationApplicationContextUtils; import com.ptc.windchill.rest.utility.error.RestMessage; import com.ptc.windchill.rest.utility.interceptors.Logged; import io.swagger.annotations.*; import wt.session.SessionServerHelper; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("/test/") @Logged @Produces({MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_JSON}) @Api(value = "/", description = "测试示例接口", tags = {"测试示例接口"}) public class TestIntegrationRestServiceResource extends BaseRestResource<TestIntegrationRestServiceImpl> implements TestIntegrationRestService { @Override public Class<TestIntegrationRestServiceImpl> getServiceImplClass() { return TestIntegrationRestServiceImpl.class; } @Override public TestIntegrationRestServiceImpl getServiceImpl() { TestIntegrationRestServiceImpl impl = TestIntegrationApplicationContextUtils.getBean("testIntegrationRestServiceImpl"); impl.setRestResource(this); return impl; } @POST @Path("queryPartInfo") @ApiOperation(value = "查询部件信息", notes = "使用部件编码进行部件信息查询") @HeaderParam("CSRF_NONCE") @ApiImplicitParams({ @ApiImplicitParam(name = "CSRF_NONCE", paramType = "header", dataType = "java.lang.String", value = "为防止跨站脚本攻击而需要设置的Token", example = "k8apbqxpRAT4RJtnq4zBDdsPCVaoMMgy8o3iG8UTB23Offwr1pXxA+EkKEiqN+Ih6umRA+RCJznCdaxUqv6fWJpaczHNdKE2/oPvBck6cn2UIexQoKfkKdoTA3SPeaY=", required = true, allowEmptyValue = false ) }) @ApiResponses(value = { @ApiResponse(code = 200, response = BaseReturnObject.class, message = "操作成功"), @ApiResponse(code = 400, response = RestMessage.class, responseContainer = "List", message = "客户端提供的参数错误,无法完成操作"), @ApiResponse(code = 500, response = RestMessage.class, responseContainer = "List", message = "服务端处理时出现异常,无法完成操作") }) @Override public Response queryPartInfo(@ApiParam(value = "查询部件信息参数", required = true, allowEmptyValue = false) QueryPartParamImpl param) { boolean enforced = SessionServerHelper.manager.setAccessEnforced(false); try { return this.getServiceImpl().queryPartInfo(param); } finally { SessionServerHelper.manager.setAccessEnforced(enforced); } } @GET @Path("userLogin") @ApiOperation(value = "用户登录认证", notes = "用户使用用户名和密码进行登录认证") @ApiResponses(value = {@ApiResponse(code = 200, response = BaseReturnObject.class, message = "操作成功"), @ApiResponse(code = 400, response = RestMessage.class, responseContainer = "List", message = "客户端提供的参数错误,无法完成操作"), @ApiResponse(code = 500, response = RestMessage.class, responseContainer = "List", message = "服务端处理时出现异常,无法完成操作")}) @Override public Response userLogin(@QueryParam("username") @ApiParam(value = "登录认证时的用户名", required = true, allowEmptyValue = false, example = "000001") String username, @QueryParam("password") @ApiParam(value = "登录认证时的密码", required = true, allowEmptyValue = false, example = "123456") String password) { boolean enforced = SessionServerHelper.manager.setAccessEnforced(false); try { return this.getServiceImpl().userLogin(username, password); } finally { SessionServerHelper.manager.setAccessEnforced(enforced); } } }GET类型的接口一般用于查询,该接口无需Token; POST类型的接口一般用于更新或者创建对象,该接口需要Token,故需要在接口入口处配置CSRF_NONC
2.3 注册REST服务REST服务注册在文件codebase/com/ptc/windchill/rest/rest.properties中,一般不建议直接修改该文件(防止内容被覆盖),而是添加至xconf文件中,执行命令传播至该文件。 在项目定制化的.xconf文件或site.xconf文件中,添加如下配置:
<!-- 注册REST接口服务 --> <Property name="test.rest.resources" overridable="true" targetFile="codebase/com/ptc/windchill/rest/rest.properties" default="xxx.xxx.integration.rest.test.service.TestIntegrationRestServiceResource"/>执行命令:xconfmanager -p 部署相关代码,重启服务
三、注解说明 注解说明@Path类开头的path用于定义注册的所有接口的url地址统一前缀;方法开头的path加上类开头的path,构成整个rest接口的完整路径@Logged记录REST API的请求和返回值输出到日志文件@ProducesHTTP返回报文的报文类型,常用的:MediaType.APPLICATION_JSON、MediaType.TEXT_PLAIN@ConsumesHTTP接收报文的报文类型,常用的:MediaType.APPLICATION_JSON、MediaType.TEXT_PLAIN@Api接口说明@GET@POST@PUT@DELETE表示被注解修饰的方法将处理(响应)来自HTTP的对应类型的请求@ApiOperation接口方法说明@ApiResponses接口返回状态码说明@PathParam标注方法的参数来自于请求的URL路径,参数的名称和@Path注解中定义的变量名对应@ApiParam参数说明@HeaderParamHTTP请求的请求头参数@ApiImplicitParams用在请求的方法上,包含一组参数说明@ApiImplicitParam用在 @ApiImplicitParams 注解中,指定一个请求参数的配置信息 四、接口调试 4.1 swagger调试站点>>实用程序>>业务管理>>首选项管理,找到“客户端自定义”,右键,设置首选项,设置为是。 此时就可以在导航栏中看到Customization: Customization>>Documentation>>API>>REST APIs (Legacy) swagger页面 用户登陆(GET)接口调试:
查询部件信息(POST)接口调试: Model页签中会显示定义的ApiModelProperty注解: 由于查询部件信息接口设置了Token,所以要先获取Token才能进行接口的调试。
4.1.1 获取Token可以通过Windchill自带的接口中获取: nonce对应的值就是Token
4.2 第三方工具调试以Reqable为例,无论哪种类型方式的调用,首先要设置授权认证 用户登陆(GET)接口调试,设置参数: 查询部件信息(POST)接口调试,设置Token:
4.3 测试类调试 4.3.1 HttpURLConnection调用工具类工具类请参考基于HTTP请求的接口调用
4.3.2 用户登陆(GET)接口调试 package test.integration.plm; import java.util.HashMap; import java.util.Map; import org.apache mons.codec.binary.Base64; import test.integration.util.HttpClientHelper; public class PLMTest { public static void main(String[] args) throws Exception { String username = "000001"; String password = "123456"; String credentials = username + ":" + password; credentials = "Basic " + Base64.encodeBase64String(credentials.getBytes()); Map<String, Object> map = new HashMap<>(); map.put("Authorization", credentials); String baseUrlPath = "http://xxx.xxx :80/Windchill/servlet/rest/test/userLogin"; Map<String, Object> params = new HashMap<>(); params.put("username", "000002"); params.put("password", "456789"); String suffix = getURLParam(params); String login_url = baseUrlPath + "?" + suffix; String login_result = HttpClientHelper.doGet(login_url, map); System.out.println(">>>>login_result=" + login_result); } public static String getURLParam(Map<String, Object> params) { StringBuffer result = new StringBuffer(); if (!params.isEmpty()) { for (String key : params.keySet()) { Object value = params.get(key); if (!result.toString().isEmpty()) { result.append("&"); } result.append(key); result.append("="); result.append(value); } } return result.toString(); } } 4.3.3 查询部件信息(POST)接口调试先调用token获取接口,然后再调用查询部件信息接口
package test.integration.plm; import java.util.HashMap; import java.util.Map; import org.apache mons.codec.binary.Base64; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import test.integration.util.HttpClientHelper; public class PLMTest { public static void main(String[] args) throws Exception { String username = "000001"; String password = "123456"; String credentials = username + ":" + password; credentials = "Basic " + Base64.encodeBase64String(credentials.getBytes()); Map<String, Object> map = new HashMap<>(); map.put("Authorization", credentials); String token_url = "http://xxx.xxx :80/Windchill/servlet/rest/security/csrf"; String token_result = IntegrationHelper.doGet(token_url, map); System.out.println(">>>>result_token=" + token_result); Map<String, String> tokenMap = getTokenResultMap(token_result); String status = tokenMap.get("status"); String result = tokenMap.get("result"); if ("success".equals(status)) { map.put("CSRF_NONCE", result); String partInfo_url = "http://xxx.xxx :80/Windchill/servlet/rest/test/queryPartInfo"; JSONObject data = new JSONObject(); data.put("username", "000002"); data.put("resource", "OA"); data.put("partNumber", "2000012300"); String partInfo_result = IntegrationHelper.doPost(partInfo_url, data.toString(), map); System.out.println(">>>>login_result=" + partInfo_result); } else { System.out.println(">>>>token获取异常=" + result); } } public static Map<String, String> getTokenResultMap(String param) { Map<String, String> map = new HashMap<>(); try { JSONObject jsonObject = JSONObject.parseObject(param); JSONArray items = (JSONArray)jsonObject.get("items"); for (Object item : items) { JSONObject object = (JSONObject)item; JSONObject attributes = (JSONObject)object.get("attributes"); String token = (String)attributes.get("nonce"); map.put("status", "success"); map.put("result", token); } } catch (Exception e) { map.put("status", "failure"); map.put("result", e.getLocalizedMessage()); } return map; } }Windchill开发-WindchillREST由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Windchill开发-WindchillREST”