瀏覽代碼

部分api增加swagger

zhouhao 8 年之前
父節點
當前提交
e662d60613
共有 28 個文件被更改,包括 465 次插入76 次删除
  1. 5 1
      hsweb-commons/hsweb-commons-controller/pom.xml
  2. 17 4
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CreateController.java
  3. 11 2
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CrudController.java
  4. 11 1
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/DeleteController.java
  5. 28 2
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/GenericEntityController.java
  6. 21 4
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/QueryController.java
  7. 28 4
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/UpdateController.java
  8. 61 33
      hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/message/ResponseMessage.java
  9. 5 0
      hsweb-commons/hsweb-commons-entity/pom.xml
  10. 6 0
      hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/PagerResult.java
  11. 2 0
      hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/SortSupportEntity.java
  12. 2 2
      hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/factory/EntityFactory.java
  13. 8 8
      hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/factory/MapperEntityFactory.java
  14. 38 0
      hsweb-commons/hsweb-commons-model/pom.xml
  15. 29 0
      hsweb-commons/hsweb-commons-model/src/main/java/org/hswebframework/web/commons/model/Model.java
  16. 3 0
      hsweb-commons/hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/CreateEntityService.java
  17. 1 1
      hsweb-commons/hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/UpdateService.java
  18. 2 2
      hsweb-commons/hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/AbstractService.java
  19. 3 3
      hsweb-commons/hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/GenericEntityService.java
  20. 6 0
      hsweb-commons/hsweb-commons-utils/pom.xml
  21. 95 0
      hsweb-commons/hsweb-commons-utils/src/main/java/org/hswebframework/web/WebUtil.java
  22. 1 0
      hsweb-commons/pom.xml
  23. 13 0
      hsweb-examples/hsweb-examples-simple/pom.xml
  24. 38 2
      hsweb-examples/hsweb-examples-simple/src/main/java/org/hswebframework/web/example/simple/SpringBootExample.java
  25. 4 1
      hsweb-examples/hsweb-examples-simple/src/main/java/org/hswebframework/web/example/simple/TestController.java
  26. 7 5
      hsweb-starter/hsweb-spring-boot-starter/src/main/java/org/hswebframework/web/starter/RestControllerExceptionTranslator.java
  27. 1 1
      hsweb-starter/hsweb-spring-boot-starter/src/main/java/org/hswebframework/web/starter/convert/FastJsonHttpMessageConverter.java
  28. 19 0
      pom.xml

+ 5 - 1
hsweb-commons/hsweb-commons-controller/pom.xml

@@ -57,6 +57,10 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-commons-model</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 </project>

+ 17 - 4
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CreateController.java

@@ -17,10 +17,14 @@
 
 package org.hswebframework.web.controller;
 
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.logging.AccessLogger;
+import org.hswebframework.web.service.CreateEntityService;
 import org.hswebframework.web.service.InsertService;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -40,15 +44,24 @@ import static org.hswebframework.web.controller.message.ResponseMessage.ok;
  * @author zhouhao
  * @since 3.0
  */
-public interface CreateController<E, PK> {
+public interface CreateController<E, PK, M> {
 
-    InsertService<E, PK> getService();
+    <S extends InsertService<E, PK> & CreateEntityService<E>> S getService();
 
     @Authorize(action = Permission.ACTION_ADD)
     @PostMapping
     @AccessLogger("{action_add}")
     @ResponseStatus(HttpStatus.CREATED)
-    default ResponseMessage add(@RequestBody E data) {
-        return ok(getService().insert(data));
+    @ApiOperation(value = "创建数据")
+    @ApiResponses({
+            @ApiResponse(code = 201, message = "创建成功,返回创建数据的ID"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限")
+    })
+    default ResponseMessage<PK> add(@RequestBody M data) {
+        E entity = getService().createEntity();
+        return ok(getService().insert(modelToEntity(data, entity)));
     }
+
+    E modelToEntity(M model, E entity);
 }

+ 11 - 2
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CrudController.java

@@ -20,6 +20,7 @@ package org.hswebframework.web.controller;
 
 import org.hswebframework.web.commons.entity.Entity;
 import org.hswebframework.web.service.CrudService;
+import org.springframework.beans.BeanUtils;
 
 /**
  * 通用增删改查控制器
@@ -32,10 +33,18 @@ import org.hswebframework.web.service.CrudService;
  * @see CrudService
  * @since 3.0
  */
-public interface CrudController<E, PK, Q extends Entity>
-        extends QueryController<E, PK, Q>, UpdateController<E, PK>, CreateController<E, PK>, DeleteController<PK> {
+public interface CrudController<E, PK, Q extends Entity, M>
+        extends QueryController<E, PK, Q>
+        , UpdateController<E, PK, M>
+        , CreateController<E, PK, M>
+        , DeleteController<PK> {
 
     @SuppressWarnings("unchecked")
     CrudService<E, PK> getService();
 
+    @Override
+    default E modelToEntity(M model, E entity) {
+        BeanUtils.copyProperties(model, entity);
+        return entity;
+    }
 }

+ 11 - 1
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/DeleteController.java

@@ -17,6 +17,9 @@
 
 package org.hswebframework.web.controller;
 
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.controller.message.ResponseMessage;
@@ -37,8 +40,15 @@ public interface DeleteController<PK> {
     DeleteService<PK> getService();
 
     @Authorize(action = Permission.ACTION_DELETE)
-    @DeleteMapping(path = "/{id}")
+    @DeleteMapping(path = "/{id:.+}")
     @AccessLogger("{delete_by_primary_key}")
+    @ApiOperation("根据ID删除数据")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "删除成功"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限"),
+            @ApiResponse(code = 404, message = "要删除的数据不存在")
+    })
     default ResponseMessage deleteByPrimaryKey(@PathVariable PK id) {
         return ok(getService().deleteByPk(id));
     }

+ 28 - 2
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/GenericEntityController.java

@@ -18,9 +18,19 @@
 
 package org.hswebframework.web.controller;
 
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.hswebframework.web.authorization.Permission;
+import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.commons.entity.Entity;
 import org.hswebframework.web.commons.entity.GenericEntity;
+import org.hswebframework.web.controller.message.ResponseMessage;
+import org.hswebframework.web.logging.AccessLogger;
 import org.hswebframework.web.service.CrudService;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 
 /**
  * 通用实体的增删改查控制器
@@ -30,8 +40,24 @@ import org.hswebframework.web.service.CrudService;
  * @see CrudController
  * @see CrudService
  */
-public interface GenericEntityController<E extends GenericEntity<PK>, PK, Q extends Entity>
-        extends CrudController<E, PK, Q> {
+public interface GenericEntityController<E extends GenericEntity<PK>, PK, Q extends Entity, M>
+        extends CrudController<E, PK, Q, M> {
 
     CrudService<E, PK> getService();
+
+    @Authorize(action = {Permission.ACTION_UPDATE, Permission.ACTION_ADD})
+    @PatchMapping(path = "/{id}")
+    @AccessLogger("{save_or_update}")
+    @ApiOperation("根据ID修改数据,如果数据不存在则新增一条数据")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "修改(新增)成功,返回数据ID"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限"),
+            @ApiResponse(code = 409, message = "存在重复的资源")
+    })
+    default ResponseMessage saveOrUpdate(@PathVariable PK id, @RequestBody M data) {
+        E entity = getService().createEntity();
+        entity.setId(id);
+        return ResponseMessage.ok(getService().saveOrUpdate(modelToEntity(data, entity)));
+    }
 }

+ 21 - 4
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/QueryController.java

@@ -17,10 +17,14 @@
 
 package org.hswebframework.web.controller;
 
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import org.hswebframework.web.NotFoundException;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.commons.entity.Entity;
+import org.hswebframework.web.commons.entity.PagerResult;
 import org.hswebframework.web.commons.entity.param.QueryParamEntity;
 import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.logging.AccessLogger;
@@ -64,18 +68,31 @@ public interface QueryController<E, PK, Q extends Entity> {
     @Authorize(action = Permission.ACTION_QUERY)
     @GetMapping
     @AccessLogger("{dynamic_query}")
-    default ResponseMessage list(Q param) {
+    @ApiOperation("根据动态条件查询数据")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "查询成功"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限")
+    })
+    default ResponseMessage<PagerResult<E>> list(Q param) {
         return ok(getService().selectPager(param));
     }
 
     @Authorize(action = Permission.ACTION_GET)
-    @GetMapping(path = "/{id}")
+    @GetMapping(path = "/{id:.+}")
     @AccessLogger("{get_by_id}")
-    default ResponseMessage getByPrimaryKey(@PathVariable PK id) {
+    @ApiOperation("根据主键查询数据")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "查询成功"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限"),
+            @ApiResponse(code = 404, message = "数据不存在")
+    })
+    default ResponseMessage<E> getByPrimaryKey(@PathVariable PK id) {
         return ok(assertNotNull(getService().selectByPk(id)));
     }
 
-    static Object assertNotNull(Object obj) {
+    static <T> T assertNotNull(T obj) {
         if (null == obj) throw new NotFoundException("{data_not_exist}");
         return obj;
     }

+ 28 - 4
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/UpdateController.java

@@ -18,10 +18,14 @@
 package org.hswebframework.web.controller;
 
 
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.logging.AccessLogger;
+import org.hswebframework.web.service.CreateEntityService;
 import org.hswebframework.web.service.UpdateService;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -32,13 +36,33 @@ import org.springframework.web.bind.annotation.RequestBody;
  *
  * @author zhouhao
  */
-public interface UpdateController<E, PK> {
-    UpdateService<E, PK> getService();
+public interface UpdateController<E, PK, M> {
+    <S extends UpdateService<E, PK> & CreateEntityService<E>> S getService();
 
     @Authorize(action = Permission.ACTION_UPDATE)
     @PutMapping(path = "/{id}")
     @AccessLogger("{update_by_primary_key}")
-    default ResponseMessage updateByPrimaryKey(@PathVariable PK id, @RequestBody E data) {
-        return ResponseMessage.ok(getService().updateByPk(id, data));
+    @ApiOperation("根据ID修改数据")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "修改成功"),
+            @ApiResponse(code = 401, message = "未授权"),
+            @ApiResponse(code = 403, message = "无权限"),
+            @ApiResponse(code = 404, message = "要修改的数据不存在"),
+            @ApiResponse(code = 409, message = "存在重复的资源")
+    })
+    default ResponseMessage updateByPrimaryKey(@PathVariable PK id, @RequestBody M data) {
+        E entity = getService().createEntity();
+        return ResponseMessage.ok(getService().updateByPk(id, modelToEntity(data, entity)));
     }
+
+    /**
+     * 将model转为entity
+     *
+     * @param model
+     * @param entity
+     * @return 转换后的结果
+     * @see org.hswebframework.web.commons.model.Model
+     * @see org.hswebframework.web.commons.entity.Entity
+     */
+    E modelToEntity(M model, E entity);
 }

+ 61 - 33
hsweb-commons/hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/message/ResponseMessage.java

@@ -20,6 +20,8 @@ package org.hswebframework.web.controller.message;
 
 
 import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
 import java.lang.reflect.Field;
@@ -28,44 +30,72 @@ import java.util.*;
 /**
  * 响应消息。controller中处理后,返回此对象,响应请求结果给客户端。
  */
-public class ResponseMessage extends LinkedHashMap<String, Object> implements Serializable {
+@ApiModel(description = "响应结果")
+public class ResponseMessage<T> implements Serializable {
     private static final long serialVersionUID = 8992436576262574064L;
 
+    private String message;
+
+    private T result;
+
+    private int status;
+
+    private Long timestamp;
+
+    @ApiModelProperty("调用结果消息")
+    public String getMessage() {
+        return message;
+    }
+
+    @ApiModelProperty(value = "状态码", required = true)
+    public int getStatus() {
+        return status;
+    }
+
+    @ApiModelProperty("成功时响应数据")
+    public T getResult() {
+        return result;
+    }
+
+    @ApiModelProperty(value = "时间戳", required = true, dataType = "Long")
+    public Long getTimestamp() {
+        return timestamp;
+    }
+
     public static ResponseMessage error(String message) {
         return error(500, message);
     }
 
     public static ResponseMessage error(int status, String message) {
         ResponseMessage msg = new ResponseMessage();
-        msg.put("message", message);
-        msg.put("status", status);
+        msg.message = message;
+        msg.status(status);
         return msg.putTimeStamp();
     }
 
-    public static ResponseMessage ok() {
+    public static <T> ResponseMessage<T> ok() {
         return ok(null);
     }
 
-    private ResponseMessage putTimeStamp() {
-        put("timestamp", System.currentTimeMillis());
+    private ResponseMessage<T> putTimeStamp() {
+        this.timestamp = System.currentTimeMillis();
         return this;
     }
 
-    public static ResponseMessage ok(Object data) {
-        return new ResponseMessage()
+    public static <T> ResponseMessage<T> ok(T data) {
+        return new ResponseMessage<T>()
                 .data(data)
                 .putTimeStamp()
                 .status(200);
     }
 
-    public ResponseMessage and(String key, Object value) {
-        put(key, value);
-        return this;
-    }
+//    public ResponseMessage and(String key, Object value) {
+//        put(key, value);
+//        return this;
+//    }
 
-    public ResponseMessage data(Object data) {
-        if (data != null)
-            put("data", data);
+    public ResponseMessage<T> data(T data) {
+        this.result = data;
         return this;
     }
 
@@ -79,14 +109,15 @@ public class ResponseMessage extends LinkedHashMap<String, Object> implements Se
      */
     private transient Map<Class<?>, Set<String>> excludes;
 
-    protected ResponseMessage() {
+    public ResponseMessage() {
+
     }
 
-    public ResponseMessage include(Class<?> type, String... fields) {
+    public ResponseMessage<T> include(Class<?> type, String... fields) {
         return include(type, Arrays.asList(fields));
     }
 
-    public ResponseMessage include(Class<?> type, Collection<String> fields) {
+    public ResponseMessage<T> include(Class<?> type, Collection<String> fields) {
         if (includes == null)
             includes = new HashMap<>();
         if (fields == null || fields.isEmpty()) return this;
@@ -107,7 +138,7 @@ public class ResponseMessage extends LinkedHashMap<String, Object> implements Se
         return this;
     }
 
-    public ResponseMessage exclude(Class type, Collection<String> fields) {
+    public ResponseMessage<T> exclude(Class type, Collection<String> fields) {
         if (excludes == null)
             excludes = new HashMap<>();
         if (fields == null || fields.isEmpty()) return this;
@@ -128,37 +159,37 @@ public class ResponseMessage extends LinkedHashMap<String, Object> implements Se
         return this;
     }
 
-    public ResponseMessage exclude(Collection<String> fields) {
+    public ResponseMessage<T> exclude(Collection<String> fields) {
         if (excludes == null)
             excludes = new HashMap<>();
         if (fields == null || fields.isEmpty()) return this;
         Class type;
-        if (getData() != null) type = getData().getClass();
+        if (getResult() != null) type = getResult().getClass();
         else return this;
         exclude(type, fields);
         return this;
     }
 
-    public ResponseMessage include(Collection<String> fields) {
+    public ResponseMessage<T> include(Collection<String> fields) {
         if (includes == null)
             includes = new HashMap<>();
         if (fields == null || fields.isEmpty()) return this;
         Class type;
-        if (getData() != null) type = getData().getClass();
+        if (getResult() != null) type = getResult().getClass();
         else return this;
         include(type, fields);
         return this;
     }
 
-    public ResponseMessage exclude(Class type, String... fields) {
+    public ResponseMessage<T> exclude(Class type, String... fields) {
         return exclude(type, Arrays.asList(fields));
     }
 
-    public ResponseMessage exclude(String... fields) {
+    public ResponseMessage<T> exclude(String... fields) {
         return exclude(Arrays.asList(fields));
     }
 
-    public ResponseMessage include(String... fields) {
+    public ResponseMessage<T> include(String... fields) {
         return include(Arrays.asList(fields));
     }
 
@@ -166,25 +197,22 @@ public class ResponseMessage extends LinkedHashMap<String, Object> implements Se
         return map.computeIfAbsent(type, k -> new HashSet<>());
     }
 
-    public Object getData() {
-        return get("data");
-    }
-
-
     @Override
     public String toString() {
         return JSON.toJSONStringWithDateFormat(this, "yyyy-MM-dd HH:mm:ss");
     }
 
-    public ResponseMessage status(int status) {
-        put("status", status);
+    public ResponseMessage<T> status(int status) {
+        this.status = status;
         return this;
     }
 
+    @ApiModelProperty(hidden = true)
     public Map<Class<?>, Set<String>> getExcludes() {
         return excludes;
     }
 
+    @ApiModelProperty(hidden = true)
     public Map<Class<?>, Set<String>> getIncludes() {
         return includes;
     }

+ 5 - 0
hsweb-commons/hsweb-commons-entity/pom.xml

@@ -48,5 +48,10 @@
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-validator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

+ 6 - 0
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/PagerResult.java

@@ -19,8 +19,12 @@
 package org.hswebframework.web.commons.entity;
 
 
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
 import java.util.List;
 
+@ApiModel(description = "分页结果")
 public class PagerResult<E> implements Entity {
     private static final long serialVersionUID = -6171751136953308027L;
     private int total;
@@ -35,6 +39,7 @@ public class PagerResult<E> implements Entity {
         this.data = data;
     }
 
+    @ApiModelProperty("数据总数量")
     public int getTotal() {
         return total;
     }
@@ -44,6 +49,7 @@ public class PagerResult<E> implements Entity {
         return this;
     }
 
+    @ApiModelProperty("查询结果")
     public List<E> getData() {
         return data;
     }

+ 2 - 0
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/SortSupportEntity.java

@@ -20,6 +20,8 @@ package org.hswebframework.web.commons.entity;
 
 public interface SortSupportEntity extends Comparable<SortSupportEntity>, Entity {
 
+    String sortIndex = "sortIndex";
+
     Long getSortIndex();
 
     void setSortIndex(Long sortIndex);

+ 2 - 2
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/factory/EntityFactory.java

@@ -35,7 +35,7 @@ public interface EntityFactory {
      * @param <T>       泛型,需实现{@link Entity}
      * @return 实体
      */
-    <T extends Entity> T newInstance(Class<T> entityClass);
+    <T> T newInstance(Class<T> entityClass);
 
     /**
      * 根据类型获取实体的真实的实体类型,
@@ -48,5 +48,5 @@ public interface EntityFactory {
      * @param <T>       泛型
      * @return 实体类型
      */
-    <T extends Entity> Class<T> getInstanceType(Class<T> entityClass);
+    <T> Class<T> getInstanceType(Class<T> entityClass);
 }

+ 8 - 8
hsweb-commons/hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/factory/MapperEntityFactory.java

@@ -38,18 +38,18 @@ public class MapperEntityFactory implements EntityFactory {
     public MapperEntityFactory() {
     }
 
-    public <T extends Entity> MapperEntityFactory(Map<Class<T>, Mapper> realTypeMapper) {
+    public <T> MapperEntityFactory(Map<Class<T>, Mapper> realTypeMapper) {
         this.realTypeMapper.putAll(realTypeMapper);
     }
 
-    public <T extends Entity> MapperEntityFactory addMapping(Class<T> target, Mapper<T> mapper) {
+    public <T> MapperEntityFactory addMapping(Class<T> target, Mapper<T> mapper) {
         realTypeMapper.put(target, mapper);
         return this;
     }
 
     @Override
     @SuppressWarnings("unchecked")
-    public <T extends Entity> T newInstance(Class<T> beanClass) {
+    public <T> T newInstance(Class<T> beanClass) {
         if (beanClass == null) return null;
         Mapper<T> mapper = realTypeMapper.get(beanClass);
         if (mapper != null) return mapper.getInstanceGetter().get();
@@ -78,7 +78,7 @@ public class MapperEntityFactory implements EntityFactory {
 
     @Override
     @SuppressWarnings("unchecked")
-    public <T extends Entity> Class<T> getInstanceType(Class<T> beanClass) {
+    public <T> Class<T> getInstanceType(Class<T> beanClass) {
         Mapper<T> mapper = realTypeMapper.get(beanClass);
         if (null != mapper) {
             return mapper.getTarget();
@@ -86,7 +86,7 @@ public class MapperEntityFactory implements EntityFactory {
         return null;
     }
 
-    public static class Mapper<T extends Entity> {
+    public static class Mapper<T> {
         Class<T>    target;
         Supplier<T> instanceGetter;
 
@@ -104,15 +104,15 @@ public class MapperEntityFactory implements EntityFactory {
         }
     }
 
-    public static <T extends Entity> Mapper<T> defaultMapper(Class<T> target) {
+    public static <T> Mapper<T> defaultMapper(Class<T> target) {
         return new Mapper<>(target, defaultInstanceGetter(target));
     }
 
-    public static <T extends Entity> Supplier<T> defaultInstanceGetter(Class<T> clazz) {
+    public static <T> Supplier<T> defaultInstanceGetter(Class<T> clazz) {
         return new DefaultInstanceGetter<>(clazz);
     }
 
-    static class DefaultInstanceGetter<T extends Entity> implements Supplier<T> {
+    static class DefaultInstanceGetter<T> implements Supplier<T> {
         Class<T> type;
 
         public DefaultInstanceGetter(Class<T> type) {

+ 38 - 0
hsweb-commons/hsweb-commons-model/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 http://www.hswebframework.org
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~        http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  ~
+  -->
+
+<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">
+    <parent>
+        <artifactId>hsweb-commons</artifactId>
+        <groupId>org.hswebframework.web</groupId>
+        <version>3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>hsweb-commons-model</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 29 - 0
hsweb-commons/hsweb-commons-model/src/main/java/org/hswebframework/web/commons/model/Model.java

@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2016 http://www.hswebframework.org
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+
+package org.hswebframework.web.commons.model;
+
+import java.io.Serializable;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ */
+public interface Model extends Serializable {
+}

+ 3 - 0
hsweb-commons/hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/CreateEntityService.java

@@ -35,4 +35,7 @@ public interface CreateEntityService<E> {
      * @return 实体
      */
     E createEntity();
+
+    Class<E> getEntityInstanceType();
+
 }

+ 1 - 1
hsweb-commons/hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/UpdateService.java

@@ -43,7 +43,7 @@ public interface UpdateService<E, PK> extends Service {
      * @param e 要修改的数据
      * @return 影响记录数
      */
-    int saveOrUpdate(E e);
+    PK saveOrUpdate(E e);
 
 
 }

+ 2 - 2
hsweb-commons/hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/AbstractService.java

@@ -51,11 +51,11 @@ public abstract class AbstractService<E extends Entity, PK> implements CreateEnt
         return null != entityFactory;
     }
 
-    protected Class<E> getEntityRealType() {
+    public Class<E> getEntityInstanceType() {
         return entityFactory.getInstanceType(getEntityType());
     }
 
-    protected Class<E> getEntityType() {
+    public Class<E> getEntityType() {
         return entityType;
     }
 

+ 3 - 3
hsweb-commons/hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/GenericEntityService.java

@@ -79,13 +79,13 @@ public abstract class GenericEntityService<E extends GenericEntity<PK>, PK>
     }
 
     @Override
-    public int saveOrUpdate(E entity) {
+    public PK saveOrUpdate(E entity) {
         if (null != entity.getId() && null != selectByPk(entity.getId())) {
-            return updateByPk(entity);
+            updateByPk(entity);
         } else {
             insert(entity);
         }
-        return 1;
+        return entity.getId();
     }
 
     @Override

+ 6 - 0
hsweb-commons/hsweb-commons-utils/pom.xml

@@ -44,6 +44,12 @@
             <optional>true</optional>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <optional>true</optional>
+        </dependency>
+
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjweaver</artifactId>

+ 95 - 0
hsweb-commons/hsweb-commons-utils/src/main/java/org/hswebframework/web/WebUtil.java

@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2016 http://www.hswebframework.org
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+
+package org.hswebframework.web;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Web常用工具集,用于获取当前登录用户,请求信息等
+ *
+ * @since 3.0
+ */
+public class WebUtil {
+
+    /**
+     * 尝试获取当前请求的HttpServletRequest实例
+     *
+     * @return HttpServletRequest
+     */
+    public static HttpServletRequest getHttpServletRequest() {
+        try {
+            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static Map<String, String> getHeaders(HttpServletRequest request) {
+        Map<String, String> map = new LinkedHashMap<>();
+        Enumeration<String> enumeration = request.getHeaderNames();
+        while (enumeration.hasMoreElements()) {
+            String key = enumeration.nextElement();
+            String value = request.getHeader(key);
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    /**
+     * 获取请求客户端的真实ip地址
+     *
+     * @param request 请求对象
+     * @return ip地址
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        String ip = request.getHeader(" x-forwarded-for ");
+        if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+        if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
+            ip = request.getHeader(" Proxy-Client-IP ");
+        }
+        if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
+            ip = request.getHeader(" WL-Proxy-Client-IP ");
+        }
+        if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+        return ip;
+    }
+
+    /**
+     * web应用绝对路径
+     *
+     * @param request 请求对象
+     * @return 绝对路径
+     */
+    public static String getBasePath(HttpServletRequest request) {
+        String path = request.getContextPath();
+        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
+        return basePath;
+    }
+
+}

+ 1 - 0
hsweb-commons/pom.xml

@@ -35,6 +35,7 @@
         <module>hsweb-commons-service</module>
         <module>hsweb-commons-controller</module>
         <module>hsweb-commons-utils</module>
+        <module>hsweb-commons-model</module>
     </modules>
 
 </project>

+ 13 - 0
hsweb-examples/hsweb-examples-simple/pom.xml

@@ -113,5 +113,18 @@
             <artifactId>hsweb-authorization-shiro</artifactId>
             <version>${project.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 38 - 2
hsweb-examples/hsweb-examples-simple/src/main/java/org/hswebframework/web/example/simple/SpringBootExample.java

@@ -19,6 +19,7 @@ package org.hswebframework.web.example.simple;
 
 import org.hsweb.ezorm.rdb.executor.AbstractJdbcSqlExecutor;
 import org.hsweb.ezorm.rdb.executor.SqlExecutor;
+import org.hswebframework.web.authorization.Authorization;
 import org.hswebframework.web.authorization.Permission;
 import org.hswebframework.web.authorization.access.DataAccess;
 import org.hswebframework.web.commons.entity.factory.EntityFactory;
@@ -35,9 +36,20 @@ import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.context.annotation.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.jdbc.datasource.DataSourceUtils;
-
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -50,8 +62,32 @@ import java.util.Arrays;
  */
 @SpringBootApplication
 @Configuration
+@EnableSwagger2
 public class SpringBootExample implements CommandLineRunner {
 
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .groupName("example")
+                .ignoredParameterTypes(HttpSession.class, Authorization.class, HttpServletRequest.class, HttpServletResponse.class)
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("org.hswebframework.web"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("hsweb 3.0 api")
+                .description("hsweb 企业后台管理基础框架")
+                .termsOfServiceUrl("http://www.hsweb.me/")
+                .license("apache 2.0")
+                .version("3.0")
+                .build();
+    }
+
+
     @Bean
     @ConditionalOnMissingBean(SqlExecutor.class)
     public SqlExecutor sqlExecutor(DataSource dataSource) {

+ 4 - 1
hsweb-examples/hsweb-examples-simple/src/main/java/org/hswebframework/web/example/simple/TestController.java

@@ -1,5 +1,6 @@
 package org.hswebframework.web.example.simple;
 
+import io.swagger.annotations.*;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.apache.shiro.authz.annotation.RequiresUser;
 import org.hswebframework.web.authorization.Authorization;
@@ -40,6 +41,8 @@ public class TestController implements QueryController<UserEntity, String, Query
 
     @GetMapping("/test")
     @RequiresPermissions("test:*")
+    @ApiOperation("测试")
+    @ApiResponse(code = 200, message = "成功")
     public ResponseMessage testShiro(Authorization authorization) {
         return ResponseMessage.ok(authorization);
     }
@@ -48,11 +51,11 @@ public class TestController implements QueryController<UserEntity, String, Query
     @RequiresUser
     @RequiresDataAccess(permission = "test", action = Permission.ACTION_QUERY)
     @RequiresFieldAccess(permission = "test", action = Permission.ACTION_QUERY)
+    @ApiOperation("测试查询")
     public ResponseMessage testQuery(QueryParamEntity entity) {
         return ResponseMessage.ok(entity);
     }
 
-
     @PutMapping("/testUpdate/{id}")
     @RequiresUser
     @RequiresDataAccess(permission = "test", action = Permission.ACTION_UPDATE)

+ 7 - 5
hsweb-starter/hsweb-spring-boot-starter/src/main/java/org/hswebframework/web/starter/RestControllerExceptionTranslator.java

@@ -17,7 +17,7 @@
 
 package org.hswebframework.web.starter;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
 import org.hswebframework.web.AuthorizeException;
 import org.hswebframework.web.AuthorizeForbiddenException;
 import org.hswebframework.web.BusinessException;
@@ -26,19 +26,21 @@ import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.validate.ValidationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.core.annotation.Order;
 import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
 
 @RestControllerAdvice
 public class RestControllerExceptionTranslator {
 
     private Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    @ExceptionHandler(ValidationException.class)
+    @ExceptionHandler(JSONException.class)
     @ResponseStatus(HttpStatus.BAD_REQUEST)
     @ResponseBody
-    ResponseMessage handleException(ValidationException exception) {
+    ResponseMessage handleException(JSONException exception) {
         return ResponseMessage.error(400, exception.getMessage());
     }
 

+ 1 - 1
hsweb-starter/hsweb-spring-boot-starter/src/main/java/org/hswebframework/web/starter/convert/FastJsonHttpMessageConverter.java

@@ -132,7 +132,7 @@ public class FastJsonHttpMessageConverter extends AbstractHttpMessageConverter<O
         out.flush();
     }
 
-    protected PropertyPreFilter[] parseFilter(ResponseMessage responseMessage) {
+    protected PropertyPreFilter[] parseFilter(ResponseMessage<?> responseMessage) {
         List<PropertyPreFilter> filters = new ArrayList<>();
         if (responseMessage.getIncludes() != null)
             for (Map.Entry<Class<?>, Set<String>> classSetEntry : responseMessage.getIncludes().entrySet()) {

+ 19 - 0
pom.xml

@@ -97,6 +97,8 @@
         <hsweb.ezorm.version>3.0.0-SNAPSHOT</hsweb.ezorm.version>
         <hsweb.utils.version>3.0.0-SNAPSHOT</hsweb.utils.version>
         <hsweb.expands.version>3.0.0-SNAPSHOT</hsweb.expands.version>
+
+        <swagger.version>2.6.1</swagger.version>
     </properties>
 
     <build>
@@ -201,6 +203,23 @@
                 <artifactId>fastjson</artifactId>
                 <version>${fastjson.version}</version>
             </dependency>
+
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger2</artifactId>
+                <version>${swagger.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger-ui</artifactId>
+                <version>${swagger.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.swagger</groupId>
+                <artifactId>swagger-annotations</artifactId>
+                <version>1.5.10</version>
+            </dependency>
             <dependency>
                 <groupId>org.hswebframework</groupId>
                 <artifactId>hsweb-utils</artifactId>