提交 24ab7fb2 编写于 作者: J Jason Song

Merge pull request #75 from yiming187/app_update

add app CRUD logic in admin service
......@@ -4,8 +4,12 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
......@@ -13,7 +17,8 @@ import com.ctrip.apollo.biz.entity.App;
import com.ctrip.apollo.biz.service.AppService;
import com.ctrip.apollo.biz.utils.BeanUtils;
import com.ctrip.apollo.core.dto.AppDTO;
import com.google.common.base.Strings;
import com.ctrip.apollo.core.exception.NotFoundException;
import com.ctrip.apollo.core.utils.StringUtils;
@RestController
public class AppController {
......@@ -21,21 +26,50 @@ public class AppController {
@Autowired
private AppService appService;
@RequestMapping("/apps/{appId}")
public AppDTO getApp(@PathVariable("appId") String appId) {
@RequestMapping(path = "/apps/", method = RequestMethod.POST)
public ResponseEntity<AppDTO> createApp(@RequestBody AppDTO appDTO) {
App app = BeanUtils.transfrom(App.class, appDTO);
app = appService.save(app);
AppDTO dto = BeanUtils.transfrom(AppDTO.class, app);
return ResponseEntity.status(HttpStatus.CREATED).body(dto);
}
@RequestMapping(path = "/apps/{appId}", method = RequestMethod.DELETE)
public void deleteApp(@PathVariable("appId") String appId) {
App app = appService.findOne(appId);
return BeanUtils.transfrom(AppDTO.class, app);
if (app == null) throw new NotFoundException("app not found for appId " + appId);
appService.delete(app.getId());
}
@RequestMapping("/apps")
public List<AppDTO> findApps(@RequestParam(value = "name", required = false) String name,
Pageable pageable) {
List<App> app = null;
if (Strings.isNullOrEmpty(name)) {
if (StringUtils.isBlank(name)) {
app = appService.findAll(pageable);
} else {
app = appService.findByName(name);
}
return BeanUtils.batchTransform(AppDTO.class, app);
}
@RequestMapping("/apps/{appId}")
public AppDTO getApp(@PathVariable("appId") String appId) {
App app = appService.findOne(appId);
if (app == null) throw new NotFoundException("app not found for appId " + appId);
return BeanUtils.transfrom(AppDTO.class, app);
}
@RequestMapping(path = "/apps/{appId}", method = RequestMethod.PUT)
public AppDTO updateApp(@PathVariable("appId") String appId, @RequestBody AppDTO appDTO) {
if (!appId.equals(appDTO.getAppId())) {
throw new IllegalArgumentException(String
.format("Path variable %s is not equals to object field %s", appId, appDTO.getAppId()));
}
App app = appService.findOne(appId);
if (app == null) throw new NotFoundException("app not found for appId " + appId);
app = appService.update(BeanUtils.transfrom(App.class, appDTO));
return BeanUtils.transfrom(AppDTO.class, app);
}
}
package com.ctrip.apollo.adminservice.controller;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.ctrip.apollo.core.exception.NotFoundException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.MediaType.APPLICATION_JSON;
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> exception(HttpServletRequest request, Exception ex) {
return handleError(request, INTERNAL_SERVER_ERROR, ex);
}
private ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request,
HttpStatus status, Throwable ex) {
return handleError(request, status, ex, ex.getMessage());
}
private ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request,
HttpStatus status, Throwable ex,
String message) {
ex = resolveError(ex);
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("status", status.value());
errorAttributes.put("message", message);
errorAttributes.put("timestamp",
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
errorAttributes.put("exception", resolveError(ex).getClass().getName());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(APPLICATION_JSON);
return new ResponseEntity<>(errorAttributes, headers, status);
}
@ExceptionHandler({HttpRequestMethodNotSupportedException.class, HttpMediaTypeException.class})
public ResponseEntity<Map<String, Object>> methodNotSupportedException(HttpServletRequest request,
ServletException ex) {
return handleError(request, BAD_REQUEST, ex);
}
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(value = NOT_FOUND)
public void notFound(HttpServletRequest req, NotFoundException ex) {
}
private Throwable resolveError(Throwable ex) {
while (ex instanceof ServletException && ex.getCause() != null) {
ex = ((ServletException) ex).getCause();
}
return ex;
}
}
......@@ -8,7 +8,6 @@ import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.http.MediaType;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
......
package com.ctrip.apollo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
@SpringBootApplication(exclude = {SampleAdminServiceApplication.class,
EurekaClientAutoConfiguration.class})
public class AdminServiceTestConfiguration {
}
package com.ctrip.apollo.adminservice.controller;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;
import com.ctrip.apollo.AdminServiceTestConfiguration;
import com.ctrip.apollo.biz.entity.App;
import com.ctrip.apollo.biz.repository.AppRepository;
import com.ctrip.apollo.biz.utils.BeanUtils;
import com.ctrip.apollo.core.dto.AppDTO;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = AdminServiceTestConfiguration.class)
@WebIntegrationTest
public class AppControllerTest {
RestTemplate restTemplate = new TestRestTemplate();
@Autowired
AppRepository appRepository;
@Test
public void testCreate() {
AppDTO dto = generateSampleDTOData();
ResponseEntity<AppDTO> response =
restTemplate.postForEntity("http://localhost:8090/apps/", dto, AppDTO.class);
AppDTO result = response.getBody();
Assert.assertEquals(HttpStatus.CREATED, response.getStatusCode());
Assert.assertEquals(dto.getAppId(), result.getAppId());
Assert.assertTrue(result.getId() > 0);
App savedApp = appRepository.findOne(result.getId());
Assert.assertEquals(dto.getAppId(), savedApp.getAppId());
Assert.assertNotNull(savedApp.getDataChangeCreatedTime());
appRepository.delete(savedApp.getId());
}
@Test
public void testFind() {
AppDTO dto = generateSampleDTOData();
App app = BeanUtils.transfrom(App.class, dto);
app = appRepository.save(app);
AppDTO result =
restTemplate.getForObject("http://localhost:8090/apps/" + dto.getAppId(), AppDTO.class);
Assert.assertEquals(dto.getAppId(), result.getAppId());
Assert.assertEquals(dto.getName(), result.getName());
appRepository.delete(app.getId());
}
@Test
public void testFindNotExist() {
ResponseEntity<AppDTO> result =
restTemplate.getForEntity("http://localhost:8090/apps/" + "notExists", AppDTO.class);
Assert.assertEquals(HttpStatus.NOT_FOUND, result.getStatusCode());
}
@Test
public void testDelete() {
AppDTO dto = generateSampleDTOData();
App app = BeanUtils.transfrom(App.class, dto);
app = appRepository.save(app);
restTemplate.delete("http://localhost:8090/apps/" + dto.getAppId());
App deletedApp = appRepository.findOne(app.getId());
Assert.assertNull(deletedApp);
}
@Test
public void testUpdate() {
AppDTO dto = generateSampleDTOData();
App app = BeanUtils.transfrom(App.class, dto);
app = appRepository.save(app);
dto.setName("newName");
restTemplate.put("http://localhost:8090/apps/" + dto.getAppId(), dto);
App updatedApp = appRepository.findOne(app.getId());
Assert.assertEquals(dto.getName(), updatedApp.getName());
Assert.assertNotNull(updatedApp.getDataChangeLastModifiedTime());
}
private AppDTO generateSampleDTOData() {
AppDTO dto = new AppDTO();
dto.setAppId("someAppId");
dto.setName("someName");
dto.setOwnerName("someOwner");
dto.setOwnerEmail("someOwner@ctrip.com");
return dto;
}
}
spring.datasource.url = jdbc:h2:mem:~/fxapolloconfigdb;mode=mysql
spring.datasource.url = jdbc:h2:mem:~/fxapolloconfigdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.h2.console.enabled = true
spring.h2.console.settings.web-allow-others=true
......@@ -9,27 +9,38 @@ import org.springframework.stereotype.Service;
import com.ctrip.apollo.biz.entity.App;
import com.ctrip.apollo.biz.repository.AppRepository;
import com.ctrip.apollo.biz.utils.BeanUtils;
@Service
public class AppService {
@Autowired
private AppRepository appRepository;
public App save(App entity){
return appRepository.save(entity);
public void delete(long id) {
appRepository.delete(id);
}
public List<App> findAll(Pageable pageable){
Page<App> page = appRepository.findAll(pageable);
return page.getContent();
public List<App> findAll(Pageable pageable) {
Page<App> page = appRepository.findAll(pageable);
return page.getContent();
}
public List<App> findByName(String name){
public List<App> findByName(String name) {
return appRepository.findByName(name);
}
public App findOne(String appId){
public App findOne(String appId) {
return appRepository.findByAppId(appId);
}
public App save(App entity) {
return appRepository.save(entity);
}
public App update(App app) {
App managedApp = appRepository.findByAppId(app.getAppId());
BeanUtils.copyEntityProperties(app, managedApp);
return appRepository.save(managedApp);
}
}
package com.ctrip.apollo.biz.utils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
......@@ -13,6 +9,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.CollectionUtils;
public class BeanUtils {
......@@ -23,7 +23,6 @@ public class BeanUtils {
* </pre>
*/
public static <T> List<T> batchTransform(final Class<T> clazz, List srcList) {
if (CollectionUtils.isEmpty(srcList)) {
return Collections.EMPTY_LIST;
}
......@@ -43,8 +42,8 @@ public class BeanUtils {
* return BeanUtil.transform(UserDTO.class, userBean);
* </pre>
*/
public static <T> T transfrom(Class<T> clazz, Object src) {
if (src == null){
public static <T> T transfrom(Class<T> clazz, Object src) {
if (src == null) {
return null;
}
T instance = null;
......@@ -208,4 +207,14 @@ public class BeanUtils {
public static List toPropertyList(String key, List list) {
return new ArrayList(toPropertySet(key, list));
}
/**
* The copy will ignore <em>id</em> field
*
* @param source
* @param target
*/
public static void copyEntityProperties(Object source, Object target) {
org.springframework.beans.BeanUtils.copyProperties(source, target, "id");
}
}
......@@ -7,6 +7,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "com.ctrip.apollo.biz")
public class SpringTestConfiguration {
public class BizTestConfiguration {
}
......@@ -8,11 +8,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ctrip.apollo.biz.SpringTestConfiguration;
import com.ctrip.apollo.biz.BizTestConfiguration;
import com.ctrip.apollo.biz.entity.App;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringTestConfiguration.class)
@SpringApplicationConfiguration(classes = BizTestConfiguration.class)
public class AppRepositoryTest {
@Autowired
......
......@@ -9,13 +9,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ctrip.apollo.biz.SpringTestConfiguration;
import com.ctrip.apollo.biz.BizTestConfiguration;
import com.ctrip.apollo.biz.entity.App;
import com.ctrip.apollo.biz.entity.Cluster;
import com.ctrip.apollo.biz.entity.Namespace;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringTestConfiguration.class)
@SpringApplicationConfiguration(classes = BizTestConfiguration.class)
public class AdminServiceTest {
@Autowired
......
......@@ -9,14 +9,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ctrip.apollo.biz.SpringTestConfiguration;
import com.ctrip.apollo.biz.BizTestConfiguration;
import com.ctrip.apollo.biz.entity.App;
import com.ctrip.apollo.biz.entity.Cluster;
import com.ctrip.apollo.biz.entity.Namespace;
import com.ctrip.apollo.biz.entity.Privilege;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringTestConfiguration.class)
@SpringApplicationConfiguration(classes = BizTestConfiguration.class)
public class PrivilegeServiceTest {
@Autowired
......
package com.ctrip.apollo.portal.exception;
package com.ctrip.apollo.core.exception;
public class NotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 7611357629749481796L;
public NotFoundException(){
}
public NotFoundException(String str){
super(str);
}
}
package com.ctrip.apollo.core.exception;
public class ServiceException extends Exception {
public class ServiceException extends RuntimeException {
/**
*
......
package com.ctrip.apollo.portal.controller;
import com.ctrip.apollo.portal.exception.NotFoundException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
......@@ -11,6 +9,8 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.ctrip.apollo.core.exception.NotFoundException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册