add open api module
This commit is contained in:
parent
94ce781ba6
commit
cd14f0b484
@ -8,7 +8,6 @@ site.context-path=
|
||||
# spring.freemarker.template-loader-path=classpath:/templates
|
||||
# spring.freemarker.suffix=.ftl
|
||||
|
||||
|
||||
# Datasource
|
||||
yo.datasource.url=jdbc:mysql://172.18.4.35/yoqw?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
|
||||
yo.datasource.username=yoqw
|
||||
|
@ -1,10 +1,14 @@
|
||||
package com.wacai.tigon.web;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
|
||||
|
||||
/**
|
||||
@ -59,26 +63,18 @@ public class JSONView extends MappingJackson2JsonView {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Object filterModel(Map<String, Object> model) {
|
||||
protected Object filterModel(final Map<String, Object> model) {
|
||||
if (dataModel == null) {
|
||||
dataModel = buildDataModel(model);
|
||||
}
|
||||
|
||||
Object dataResp;
|
||||
final JSONViewDataModelAssembler dataModelAssembler =
|
||||
config.getDataModelAssembler();
|
||||
if (dataModelAssembler != null) {
|
||||
dataResp = dataModelAssembler.assemble(dataModel);
|
||||
if (dataResp instanceof JSONViewDataModel) {
|
||||
dataResp = ((JSONViewDataModel) dataResp).toMap(
|
||||
config.getSuccessKey(), config.getDataKey(),
|
||||
config.getCodeKey(), config.getMessageKey());
|
||||
}
|
||||
}
|
||||
else {
|
||||
dataResp = dataModel.toMap(config.getSuccessKey(),
|
||||
config.getDataKey(), config.getCodeKey(), config.getMessageKey());
|
||||
dataModelAssembler.assemble(dataModel);
|
||||
}
|
||||
|
||||
final Object dataResp = toMap(dataModel);
|
||||
log.debug("Render JSON response [{}].", dataResp);
|
||||
return dataResp;
|
||||
}
|
||||
@ -120,4 +116,53 @@ public class JSONView extends MappingJackson2JsonView {
|
||||
}
|
||||
return new JSONViewDataModel(objData);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap(final JSONViewDataModel model) {
|
||||
|
||||
final Map<String, Object> mapData = new HashMap<>(4);
|
||||
final Map<String, Object> attrs = model.getAttrs();
|
||||
if (attrs != null) {
|
||||
mapData.putAll(attrs);
|
||||
}
|
||||
|
||||
final Object data = model.getData();
|
||||
if (data != null) {
|
||||
final String dataKey = config.getDataKey();
|
||||
if (StringUtils.isNotBlank(dataKey)) {
|
||||
mapData.put(dataKey, data);
|
||||
}
|
||||
else {
|
||||
final ObjectMapper objectMapper = getObjectMapper();
|
||||
final JsonNode jsonNode = objectMapper.valueToTree(data);
|
||||
if (jsonNode.isObject()) {
|
||||
try {
|
||||
mapData.putAll(
|
||||
objectMapper.treeToValue(jsonNode, Map.class));
|
||||
}
|
||||
catch (final JsonProcessingException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mapData.put("data", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final boolean success = model.isSuccess();
|
||||
mapData.put(config.getSuccessKey(), success);
|
||||
Object code = model.getCode();
|
||||
if ("string".equalsIgnoreCase(config.getCodeType())) {
|
||||
if (!(code instanceof CharSequence)) {
|
||||
code = code.toString();
|
||||
}
|
||||
}
|
||||
|
||||
mapData.put(config.getCodeKey(), code);
|
||||
if (!success) {
|
||||
mapData.put(config.getMessageKey(),
|
||||
model.getMessageOrExceptionMessage());
|
||||
}
|
||||
return mapData;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ public class JSONViewConfig {
|
||||
private String dataKey;
|
||||
@Value("${tigon.web.jsonview.code-key:code}")
|
||||
private String codeKey;
|
||||
@Value("${tigon.web.jsonview.code-type:int}")
|
||||
private String codeType;
|
||||
@Value("${tigon.web.jsonview.success-code:0}")
|
||||
private String successCode;
|
||||
@Value("${tigon.web.jsonview.message-key:error}")
|
||||
private String messageKey;
|
||||
@Autowired(required = false)
|
||||
|
@ -1,7 +1,8 @@
|
||||
package com.wacai.tigon.web;
|
||||
|
||||
import lombok.Getter;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@ -20,6 +21,7 @@ public class JSONViewDataModel {
|
||||
private Object message;
|
||||
private Object data;
|
||||
private Map<String, Object> attrs;
|
||||
@Setter
|
||||
private Throwable exception;
|
||||
|
||||
/**
|
||||
@ -71,37 +73,6 @@ public class JSONViewDataModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return formatted data map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> toMap(
|
||||
final String successKey,
|
||||
final String dataKey,
|
||||
final String codeKey,
|
||||
final String messageKey) {
|
||||
Map<String, Object> mapData = new HashMap<>(4);
|
||||
if (attrs != null) {
|
||||
mapData.putAll(attrs);
|
||||
}
|
||||
if (data != null) {
|
||||
mapData.put(dataKey, data);
|
||||
}
|
||||
mapData.put(successKey, success);
|
||||
mapData.put(codeKey, code);
|
||||
if (!success) {
|
||||
mapData.put(messageKey, getMessageOrExceptionMessage());
|
||||
}
|
||||
return mapData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception the exception to set
|
||||
*/
|
||||
public void setException(Throwable exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attrs the attrs to set
|
||||
* @return this
|
||||
|
@ -13,5 +13,5 @@ public interface JSONViewDataModelAssembler {
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
Object assemble(JSONViewDataModel model);
|
||||
void assemble(JSONViewDataModel model);
|
||||
}
|
||||
|
101
openapi/pom.xml
Normal file
101
openapi/pom.xml
Normal file
@ -0,0 +1,101 @@
|
||||
<?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>
|
||||
<artifactId>yo-openapi</artifactId>
|
||||
<version>0.0.1-RELEASE</version>
|
||||
<name>Yo Open API</name>
|
||||
<description>Yo Open API</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<spring-boot.run.main-class>com.pudonghot.yo.openapi.YoOpenAPI</spring-boot.run.main-class>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-fsagent-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-openapi-dto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-mapper</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-redis-raw</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.wacai.tigon</groupId>
|
||||
<artifactId>tigon-shiro</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.wacai.tigon</groupId>
|
||||
<artifactId>tigon-service-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.wacai.tigon</groupId>
|
||||
<artifactId>tigon-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-web-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-dependencies-zookeeper</artifactId>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<!-- Provided Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,20 @@
|
||||
package com.pudonghot.yo.openapi;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 15:56:08
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class YoOpenAPI {
|
||||
|
||||
/**
|
||||
* main
|
||||
* @param args args
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
SpringApplication.run(YoOpenAPI.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import com.wacai.tigon.shiro.AuthRealm;
|
||||
import com.wacai.tigon.shiro.model.Credential;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.pudonghot.yo.model.domain.Tenant;
|
||||
import org.apache.shiro.authc.UnknownAccountException;
|
||||
import org.apache.shiro.authc.DisabledAccountException;
|
||||
import com.pudonghot.yo.openapi.service.TenantService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Nov 08, 2019 15:41:20
|
||||
*/
|
||||
@Component
|
||||
public class AuthRealmSupport implements AuthRealm<String> {
|
||||
@Autowired
|
||||
private TenantService tenantService;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Credential<String> credential(final String principal) {
|
||||
final Tenant tenant = tenantService.find(
|
||||
new Search(Tenant.ACCESS_KEY, principal));
|
||||
|
||||
if (tenant == null) {
|
||||
throw new UnknownAccountException(
|
||||
"Unknown account [" + principal + "]");
|
||||
}
|
||||
|
||||
if (tenant != null) {
|
||||
if (!tenant.getActive()) {
|
||||
throw new DisabledAccountException("Account disabled");
|
||||
}
|
||||
final Credential<String> credential = new Credential<>(
|
||||
tenant.getAccessSecret(),
|
||||
principal);
|
||||
credential.setExtra(tenant);
|
||||
return credential;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean credentialMatch(final Object password, final Credential<String> credential) {
|
||||
return credential.getCredential().equals(new String((char[]) password));
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Nov 17, 2019 16:30:41
|
||||
*/
|
||||
@Order
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AuthRequestFilter implements Filter {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
log.debug("Wrap HTTP servlet request as AUTH request.");
|
||||
filterChain.doFilter(new AuthRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Jan 03, 2020 18:18:28
|
||||
*/
|
||||
public class AuthRequestWrapper extends HttpServletRequestWrapper implements SessionAbility {
|
||||
private static Map<String, Function<SessionAbility, ?>> AUTH_ELS = new HashMap<>();
|
||||
static {
|
||||
AUTH_ELS.put(Agent.TENANT_ID, SessionAbility::getTenantId);
|
||||
AUTH_ELS.put(Agent.TENANT_CODE, SessionAbility::getTenantCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public AuthRequestWrapper(final HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Enumeration<String> getParameterNames() {
|
||||
final Enumeration<String> paramNames = super.getParameterNames();
|
||||
|
||||
if (isAuthenticated()) {
|
||||
final List<String> params = Collections.list(paramNames);
|
||||
params.addAll(AUTH_ELS.keySet());
|
||||
return Collections.enumeration(params);
|
||||
}
|
||||
return paramNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String[] getParameterValues(final String name) {
|
||||
final Function<SessionAbility, ?> getter = AUTH_ELS.get(name);
|
||||
return getter != null ? new String[] { getParam(getter) } : super.getParameterValues(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* get params
|
||||
* @param getter getter
|
||||
* @return param string or null
|
||||
*/
|
||||
private String getParam(final Function<SessionAbility, ?> getter) {
|
||||
final Object param = getter.apply(this);
|
||||
return param != null ?
|
||||
(param instanceof String ?
|
||||
(String) param : String.valueOf(param)) : null;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import com.pudonghot.yo.model.domain.Tenant;
|
||||
import com.pudonghot.yo.openapi.service.TenantService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Sep 11, 2019 17:03:44
|
||||
*/
|
||||
@Validated
|
||||
public interface SessionAbility {
|
||||
|
||||
/**
|
||||
* get current tenant
|
||||
*
|
||||
* @return tenant
|
||||
*/
|
||||
default Tenant getTenant() {
|
||||
return getTenant(getAccessKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* get tenant id
|
||||
*
|
||||
* @return tenant id
|
||||
*/
|
||||
default Integer getTenantId() {
|
||||
return getTenant(getAccessKey()).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* get tenant code
|
||||
*
|
||||
* @return tenant code
|
||||
*/
|
||||
default String getTenantCode() {
|
||||
return getTenant(getAccessKey()).getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* get access key tenant
|
||||
*
|
||||
* @param accessKey account
|
||||
* @return bu of account
|
||||
*/
|
||||
default Tenant getTenant(final String accessKey) {
|
||||
final TenantService tenantService =
|
||||
SessionServiceHolder.getTenantService();
|
||||
final Tenant tenant = tenantService.find(
|
||||
new Search(Tenant.ACCESS_KEY, accessKey)
|
||||
.eq(Tenant.ACTIVE, true));
|
||||
Assert.state(tenant != null, "无效租户");
|
||||
return tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* get session access key
|
||||
*
|
||||
* @return session access key
|
||||
*/
|
||||
default String getAccessKey() {
|
||||
return (String) SecurityUtils.getSubject().getPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if user is authenticated
|
||||
*
|
||||
* @return true if user is authenticated
|
||||
*/
|
||||
default boolean isAuthenticated() {
|
||||
return SecurityUtils.getSubject().isAuthenticated();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.web.servlet.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.wacai.tigon.shiro.SessionIdManager;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Nov 08, 2019 15:42:25
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SessionIdManagerSupport implements SessionIdManager {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Serializable read(HttpServletRequest request, HttpServletResponse response, Cookie cookie) {
|
||||
final String acToken = request.getHeader("x-ac-token");
|
||||
log.debug("Achieve access token [{}] from HTTP request header.", acToken);
|
||||
return acToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean write(HttpServletRequest request, HttpServletResponse response, Cookie cookie) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.pudonghot.yo.openapi.auth;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.pudonghot.yo.openapi.service.TenantService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Sep 11, 2019 16:57:24
|
||||
*/
|
||||
@Getter
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
|
||||
public class SessionServiceHolder implements InitializingBean {
|
||||
private static SessionServiceHolder holder;
|
||||
|
||||
private final TenantService tenantService;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
holder = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* get tenant service
|
||||
*
|
||||
* @return tenant service
|
||||
*/
|
||||
public static TenantService getTenantService() {
|
||||
return holder.tenantService;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import org.springframework.util.Assert;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import com.pudonghot.yo.model.domain.Tenant;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.openapi.auth.SessionAbility;
|
||||
import com.pudonghot.yo.openapi.dto.response.SipInfo;
|
||||
import com.pudonghot.yo.openapi.service.AgentService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 16:02:19
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/v1/agent")
|
||||
public class AgentController implements SessionAbility {
|
||||
@Autowired
|
||||
private AgentService agentService;
|
||||
@Value("${sip.proxy:wss://loan.wacai.info/yo-webrtc/opt}")
|
||||
private String sipProxy;
|
||||
|
||||
@RequestMapping("/find")
|
||||
public Agent find(@RequestParam("id") final Integer id) {
|
||||
return agentService.find(id);
|
||||
}
|
||||
|
||||
@RequestMapping("/sip-info")
|
||||
public SipInfo sipInfo(
|
||||
@NotBlank
|
||||
@RequestParam("account")
|
||||
final String account) {
|
||||
|
||||
final Tenant tenant = getTenant();
|
||||
final SipInfo sipInfo = new SipInfo();
|
||||
sipInfo.setRealm(tenant.getRealm());
|
||||
sipInfo.setProxy(sipProxy);
|
||||
sipInfo.setAccount(account);
|
||||
final Agent agent = agentService.find(
|
||||
new Search(Agent.TENANT_ID, tenant.getId())
|
||||
.eq(Agent.ACCOUNT, account));
|
||||
Assert.state(agent != null,
|
||||
() -> "No agent [" + account + "] found");
|
||||
Assert.state(agent.getActive(),
|
||||
() -> "Agent [" + account + "] is not active");
|
||||
sipInfo.setAgent(agent.getAgent());
|
||||
sipInfo.setPassword(agent.getPassword());
|
||||
return sipInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.wacai.tigon.web.JSONViewConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Jan 03, 2020 19:29:11
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class AppErrorController implements ErrorController {
|
||||
/**
|
||||
* Error Attributes in the Application
|
||||
*/
|
||||
private final ErrorAttributes errorAttributes;
|
||||
private final static String ERROR_PATH = "/error";
|
||||
@Autowired
|
||||
private JSONViewConfig jsonViewConfig;
|
||||
|
||||
/**
|
||||
* Supports other formats like JSON, XML
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = ERROR_PATH)
|
||||
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
|
||||
final Map<String, Object> body =
|
||||
errorAttributes.getErrorAttributes(
|
||||
new ServletWebRequest(request), getTraceParam(request));
|
||||
body.put(jsonViewConfig.getSuccessKey(), false);
|
||||
final HttpStatus status = getStatus(request);
|
||||
body.put(jsonViewConfig.getCodeKey(), status.value());
|
||||
return new ResponseEntity<>(body, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the error page.
|
||||
*
|
||||
* @return the error path
|
||||
*/
|
||||
@Override
|
||||
public String getErrorPath() {
|
||||
return ERROR_PATH;
|
||||
}
|
||||
|
||||
private boolean getTraceParam(final HttpServletRequest request) {
|
||||
final String paramTrace = request.getParameter("trace");
|
||||
if (paramTrace == null) {
|
||||
return false;
|
||||
}
|
||||
return !"false".equals(paramTrace.toLowerCase());
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
final Integer statusCode = (Integer) request.getAttribute(
|
||||
"javax.servlet.error.status_code");
|
||||
if (statusCode != null) {
|
||||
try {
|
||||
return HttpStatus.valueOf(statusCode);
|
||||
}
|
||||
catch (final Exception e) {
|
||||
log.error("Parse HTTP status code error caused.", e);
|
||||
}
|
||||
}
|
||||
return HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import com.pudonghot.yo.openapi.auth.SessionAbility;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import com.pudonghot.yo.openapi.dto.request.AuthSignIn;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.yo.openapi.dto.response.AccessTokeInfo;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Mar 14, 2017 14:59:22
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/v1/auth")
|
||||
public class AuthController implements SessionAbility {
|
||||
|
||||
@PostMapping("/sign-in")
|
||||
public AccessTokeInfo signIn(final AuthSignIn form) {
|
||||
final String accessKey = form.getAccessKey();
|
||||
final Subject secSubject = SecurityUtils.getSubject();
|
||||
secSubject.login(
|
||||
new UsernamePasswordToken(accessKey,
|
||||
form.getAccessSecret()));
|
||||
|
||||
return buildAccessTokeInfo(secSubject, accessKey);
|
||||
}
|
||||
|
||||
@GetMapping("/access-token")
|
||||
public AccessTokeInfo accessToken() {
|
||||
return buildAccessTokeInfo(
|
||||
SecurityUtils.getSubject(), getTenantCode());
|
||||
}
|
||||
|
||||
private AccessTokeInfo buildAccessTokeInfo(
|
||||
final Subject secSubject, final String tenantCode) {
|
||||
|
||||
final Session session = secSubject.getSession(false);
|
||||
final AccessTokeInfo accessTokeInfo = new AccessTokeInfo();
|
||||
accessTokeInfo.setToken((String) session.getId());
|
||||
accessTokeInfo.setTenantCode(tenantCode);
|
||||
accessTokeInfo.setExpireAt(
|
||||
session.getStartTimestamp().getTime() + session.getTimeout());
|
||||
return accessTokeInfo;
|
||||
}
|
||||
|
||||
@PostMapping("/sign-out")
|
||||
public void signOut() {
|
||||
SecurityUtils.getSubject().logout();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.wacai.tigon.web.JSONViewDataModel;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import com.pudonghot.yo.openapi.form.BaseForm;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import com.pudonghot.yo.openapi.auth.SessionAbility;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.apache.shiro.authc.IncorrectCredentialsException;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @Bingpo
|
||||
* @date Nov 09, 2019 15:03:43
|
||||
*/
|
||||
@Slf4j
|
||||
@ControllerAdvice(annotations = {Controller.class, RestController.class})
|
||||
public class BaseControllerAdvice implements SessionAbility {
|
||||
|
||||
@ExceptionHandler(IncorrectCredentialsException.class)
|
||||
public JSONViewDataModel incorrectCredentialsException(IncorrectCredentialsException ex) {
|
||||
log.warn("Incorrect credentials exception [{}] [{}] caused.", ex.getClass(), ex.getMessage());
|
||||
final JSONViewDataModel model = new JSONViewDataModel(ex).setSuccess(false);
|
||||
model.setCode(403);
|
||||
model.setMessage("Incorrect credentials");
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* controller init bind
|
||||
*
|
||||
* @param binder binder
|
||||
* @throws IllegalAccessException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
@InitBinder
|
||||
public void initDataBind(final WebDataBinder binder) {
|
||||
|
||||
final Object target = binder.getTarget();
|
||||
|
||||
if (target instanceof BaseForm) {
|
||||
log.debug("Bind tenant to request body [{}].", target);
|
||||
((BaseForm) target).setTenantId(getTenantId());
|
||||
((BaseForm) target).setTenantCode(getTenantCode());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.fsagent.api.DialService;
|
||||
import com.pudonghot.yo.openapi.dto.request.AgentDial;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.yo.openapi.dto.response.AgentDialResp;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Jan 03, 2020 18:20:59
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/v1")
|
||||
public class DialController {
|
||||
@Autowired
|
||||
private DialService dialService;
|
||||
|
||||
@RequestMapping("/dial")
|
||||
public AgentDialResp dial(final AgentDial req) {
|
||||
return new AgentDialResp(dialService.agentDial(
|
||||
req.copy(new ReqAgentDial())).getUuid());
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 15:57:14
|
||||
*/
|
||||
@Controller
|
||||
public class SiteController {
|
||||
|
||||
@GetMapping("/")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@GetMapping("/int")
|
||||
public int testInt() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
@GetMapping("/map")
|
||||
public Map<String, Object> testMap() {
|
||||
final Map<String, Object> mapRtn = new HashMap<>();
|
||||
mapRtn.put("gid", 42);
|
||||
return mapRtn;
|
||||
}
|
||||
|
||||
@GetMapping("/agent")
|
||||
public Agent testAgent() {
|
||||
final Agent agent = new Agent();
|
||||
agent.setId(42);
|
||||
agent.setAccount("donghuang");
|
||||
agent.setName("Donghuang");
|
||||
return agent;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.pudonghot.yo.openapi.form;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author bingpo
|
||||
* @author Donghuang
|
||||
* @date 2020/2/10 上午11:00
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class BaseForm {
|
||||
@NotNull
|
||||
private Integer tenantId;
|
||||
@NotBlank
|
||||
private String tenantCode;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.pudonghot.yo.openapi.service;
|
||||
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import com.wacai.tigon.service.BaseCrudService;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 15:59:44
|
||||
*/
|
||||
public interface AgentService extends BaseCrudService<Integer, Agent> {
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.pudonghot.yo.openapi.service;
|
||||
|
||||
import com.wacai.tigon.service.BaseCrudService;
|
||||
import com.pudonghot.yo.model.domain.Tenant;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 15:59:44
|
||||
*/
|
||||
public interface TenantService extends BaseCrudService<Integer, Tenant> {
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.pudonghot.yo.openapi.service.impl;
|
||||
|
||||
import com.pudonghot.yo.openapi.service.AgentService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.yo.mapper.AgentMapper;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import com.wacai.tigon.service.support.BaseCrudServiceSupport;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 15:59:54
|
||||
*/
|
||||
@Service
|
||||
public class AgentServiceImpl
|
||||
extends BaseCrudServiceSupport<Integer, Agent, AgentMapper>
|
||||
implements AgentService {
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.pudonghot.yo.openapi.service.impl;
|
||||
|
||||
import com.pudonghot.yo.openapi.service.TenantService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.yo.mapper.TenantMapper;
|
||||
import com.pudonghot.yo.model.domain.Tenant;
|
||||
import com.wacai.tigon.service.support.BaseCrudServiceSupport;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Nov 01, 2019 15:43:13
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TenantServiceImpl
|
||||
extends BaseCrudServiceSupport<Integer,
|
||||
Tenant,
|
||||
TenantMapper>
|
||||
implements TenantService {
|
||||
}
|
35
openapi/src/main/resources/application.properties
Normal file
35
openapi/src/main/resources/application.properties
Normal file
@ -0,0 +1,35 @@
|
||||
server.port=8081
|
||||
spring.application.name=yo-openapi
|
||||
spring.jackson.time-zone=GMT+8
|
||||
spring.jackson.serialization.write-dates-as-timestamps=true
|
||||
spring.jackson.serialization.fail-on-empty-beans=false
|
||||
|
||||
tigon.web.jsonview.success-key=success
|
||||
tigon.web.jsonview.data-key=
|
||||
tigon.web.jsonview.code-key=rtncode
|
||||
tigon.web.jsonview.code-type=string
|
||||
tigon.web.jsonview.message-key=message
|
||||
|
||||
# Datasource
|
||||
yo.datasource.url=jdbc:mysql://172.18.4.35/yoqw?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
|
||||
yo.datasource.username=yoqw
|
||||
yo.datasource.password=yoqw_query!
|
||||
|
||||
# Redis
|
||||
yo.redis.host=172.16.92.232
|
||||
yo.redis.port=6379
|
||||
yo.redis.password=123456
|
||||
|
||||
# Shiro
|
||||
tigon.shiro.filter-chain=/v1/auth/sign-in=anon \
|
||||
/=anon \
|
||||
/index.html=anon \
|
||||
/assets/**=anon \
|
||||
/**=anon
|
||||
|
||||
# Dubbo
|
||||
|
||||
## Dubbo Registry
|
||||
dubbo.registry.address=zookeeper://172.16.67.223:2181
|
||||
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
|
||||
yo.fsagent.dubbo.service.version=1.0.0
|
36
openapi/src/main/resources/logback.xml
Normal file
36
openapi/src/main/resources/logback.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="true" scan="true" scanPeriod="180 seconds">>
|
||||
|
||||
<property name="log.level" value="DEBUG" />
|
||||
<property name="log.dir" value="${project.basedir}/.logs" />
|
||||
|
||||
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/${project.artifactId}.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread] %-5level %logger{15} %msg %n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/%d{yyyy-MM, aux}/${project.artifactId}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>32MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="${log.level}" additivity="false">
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="File" />
|
||||
</logger>
|
||||
<root level="${log.level}">
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="File" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
13
openapi/src/main/resources/spring/spring-yo-openapi.xml
Normal file
13
openapi/src/main/resources/spring/spring-yo-openapi.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<dubbo:reference id="dialService"
|
||||
interface="com.pudonghot.yo.fsagent.api.DialService"
|
||||
version="${yo.fsagent.dubbo.service.version}" />
|
||||
</beans>
|
@ -0,0 +1 @@
|
||||
OK
|
@ -0,0 +1,34 @@
|
||||
package com.pudonghot.yo.openapi;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.fsagent.api.DialService;
|
||||
import com.pudonghot.yo.fsagent.api.response.RespDial;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Dec 12, 2019 23:59:37
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = YoOpenAPI.class)
|
||||
public class TestDialService {
|
||||
|
||||
@Autowired
|
||||
private DialService dialService;
|
||||
|
||||
@Test
|
||||
public void testDial() {
|
||||
final ReqAgentDial req = new ReqAgentDial();
|
||||
req.setTenantId(13);
|
||||
req.setAccount("donghuang");
|
||||
req.setCalledNumber("13764268709");
|
||||
final RespDial resp = dialService.agentDial(req);
|
||||
log.info("Dial result [{}].", resp);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.pudonghot.yo.openapi;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.util.UUID;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Oct 26, 2019 20:27:23
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestDriver {
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
final String id = Long.toHexString(uuid.getMostSignificantBits())
|
||||
+ Long.toHexString(uuid.getLeastSignificantBits());
|
||||
log.info("UUID: {}", id);
|
||||
}
|
||||
}
|
14
openapi/src/test/resources/spring/spring-test.xml
Normal file
14
openapi/src/test/resources/spring/spring-test.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<dubbo:reference id="demoService"
|
||||
interface="com.pudonghot.yo.fsagent.api.DemoService"
|
||||
version="${yo.fsagent.dubbo.service.version}"
|
||||
/>
|
||||
</beans>
|
Loading…
x
Reference in New Issue
Block a user