From 52094ec13799af5020e2d0b2700c858737021799 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Wed, 11 Jul 2018 14:52:11 +0800 Subject: [PATCH] :bookmark: javaapp --- demos/javaapp/pom.xml | 17 +++ .../java/io/github/dunwu/{app => }/Main.java | 2 +- .../io/github/dunwu/filter/CorsFilter.java | 103 +++++++++++++++ .../io/github/dunwu/util/IOObjectMapper.java | 12 ++ .../dunwu/web/controller/ApiController.java | 108 ++++++++++++++++ .../controller/HelloController.java | 2 +- .../controller/IndexController.java | 2 +- .../github/dunwu/web/dto/BaseResponseDTO.java | 87 +++++++++++++ .../java/io/github/dunwu/web/dto/MenuDTO.java | 122 ++++++++++++++++++ .../main/resources/spring/spring-servlet.xml | 10 +- .../src/main/webapp/META-INF/MANIFEST.MF | 2 +- demos/javaapp/src/main/webapp/WEB-INF/web.xml | 18 +++ 12 files changed, 480 insertions(+), 5 deletions(-) rename demos/javaapp/src/main/java/io/github/dunwu/{app => }/Main.java (99%) create mode 100644 demos/javaapp/src/main/java/io/github/dunwu/filter/CorsFilter.java create mode 100644 demos/javaapp/src/main/java/io/github/dunwu/util/IOObjectMapper.java create mode 100644 demos/javaapp/src/main/java/io/github/dunwu/web/controller/ApiController.java rename demos/javaapp/src/main/java/io/github/dunwu/{app => web}/controller/HelloController.java (95%) rename demos/javaapp/src/main/java/io/github/dunwu/{app => web}/controller/IndexController.java (94%) create mode 100644 demos/javaapp/src/main/java/io/github/dunwu/web/dto/BaseResponseDTO.java create mode 100644 demos/javaapp/src/main/java/io/github/dunwu/web/dto/MenuDTO.java diff --git a/demos/javaapp/pom.xml b/demos/javaapp/pom.xml index 3491f31..aadcc99 100644 --- a/demos/javaapp/pom.xml +++ b/demos/javaapp/pom.xml @@ -52,6 +52,23 @@ ${tomcat.version} + + + org.apache.commons + commons-lang3 + 3.7 + + + ch.qos.logback + logback-classic + 1.1.2 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.6 + + diff --git a/demos/javaapp/src/main/java/io/github/dunwu/app/Main.java b/demos/javaapp/src/main/java/io/github/dunwu/Main.java similarity index 99% rename from demos/javaapp/src/main/java/io/github/dunwu/app/Main.java rename to demos/javaapp/src/main/java/io/github/dunwu/Main.java index 783c451..b6fe78e 100644 --- a/demos/javaapp/src/main/java/io/github/dunwu/app/Main.java +++ b/demos/javaapp/src/main/java/io/github/dunwu/Main.java @@ -1,4 +1,4 @@ -package io.github.dunwu.app; +package io.github.dunwu; import java.io.File; import org.apache.catalina.Server; diff --git a/demos/javaapp/src/main/java/io/github/dunwu/filter/CorsFilter.java b/demos/javaapp/src/main/java/io/github/dunwu/filter/CorsFilter.java new file mode 100644 index 0000000..46f8320 --- /dev/null +++ b/demos/javaapp/src/main/java/io/github/dunwu/filter/CorsFilter.java @@ -0,0 +1,103 @@ +package io.github.dunwu.filter; + +import java.io.IOException; +import java.util.regex.Pattern; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 跨域过滤器,根据正则进行匹配 + */ +public class CorsFilter implements Filter { + private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class); + + private String regex; + private String headerKey; + private String protocol = "http"; + private final String ORIGIN_KEY = "Origin"; + + public void init(FilterConfig filterConfig) { + // 取配置参数 + regex = filterConfig.getInitParameter("regex"); + headerKey = filterConfig.getInitParameter("headerKey"); + String protocolVal = filterConfig.getInitParameter("protocol"); + if (StringUtils.isNotBlank(protocolVal)) { + if (StringUtils.equalsIgnoreCase("http", protocolVal) + || StringUtils.equalsIgnoreCase("https", protocolVal)) { + protocol = protocolVal.toLowerCase(); + } else { + logger.error("CorsFilter 配置参数 protocol 非法,仍使用默认值 http"); + } + } + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + if (StringUtils.isBlank(regex) || StringUtils.isBlank(headerKey)) { + throw new ServletException("读取跨域过滤器的配置参数失败"); + } + + // 读取请求地址的域 + String domain = httpRequest.getHeader(headerKey); + String origin = httpRequest.getHeader(ORIGIN_KEY); + + if (StringUtils.isBlank(origin)) { + logger.debug("origin 为空, 跳过检查"); + chain.doFilter(httpRequest, httpResponse); + return; + } + + if (StringUtils.isBlank(domain)) { + logger.debug("domain 为空, 跳过检查"); + chain.doFilter(httpRequest, httpResponse); + return; + } + + if (origin.toLowerCase().contains(domain.toLowerCase())) { + // 判断请求方和应答方是否同为 http 或 https + // 如果相同,这里视为同源;否则,视为跨域 + if (origin.startsWith(protocol)) { + logger.debug("domain={}, origin={}, 二者协议相同,且域名同源,跳过检查", domain, origin); + chain.doFilter(httpRequest, httpResponse); + return; + } + } + + Pattern pattern = Pattern.compile(regex); + if (!pattern.matcher(origin).matches()) { + logger.warn("客户端域 origin={} 不在跨域白名单中", origin); + httpResponse.sendError(403, "客户端域不在跨域白名单中"); + throw new ServletException("客户端域不在跨域白名单中"); + } + + logger.debug("对 origin={} 放开跨域限制", origin); + httpResponse.addHeader("Access-Control-Allow-Origin", origin); + httpResponse.addHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE"); + httpResponse.addHeader("Access-Control-Allow-Headers", + "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," + + " Cache-Control, Content-Type, Content-Range, Range, X-CSRF-TOKEN"); + httpResponse.addHeader("Access-Control-Expose-Headers", + "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," + + " Cache-Control, Content-Type, Content-Range, Range"); + if (httpRequest.getMethod().equals("OPTIONS")) { + httpResponse.setStatus(HttpServletResponse.SC_OK); + return; + } + chain.doFilter(httpRequest, httpResponse); + } + + public void destroy() {} +} diff --git a/demos/javaapp/src/main/java/io/github/dunwu/util/IOObjectMapper.java b/demos/javaapp/src/main/java/io/github/dunwu/util/IOObjectMapper.java new file mode 100644 index 0000000..d275ccf --- /dev/null +++ b/demos/javaapp/src/main/java/io/github/dunwu/util/IOObjectMapper.java @@ -0,0 +1,12 @@ +package io.github.dunwu.util; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class IOObjectMapper extends ObjectMapper { + public IOObjectMapper() { + this.setSerializationInclusion(Include.NON_EMPTY); + this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } +} diff --git a/demos/javaapp/src/main/java/io/github/dunwu/web/controller/ApiController.java b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/ApiController.java new file mode 100644 index 0000000..9094291 --- /dev/null +++ b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/ApiController.java @@ -0,0 +1,108 @@ +package io.github.dunwu.web.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.dunwu.web.dto.BaseResponseDTO; +import io.github.dunwu.web.dto.MenuDTO; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +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.ResponseBody; + +/** + * 配合前端请求的 API 接口 + * @author zhangpeng0913 + * @date 2017/8/23. + */ +@Controller +@RequestMapping(value = "/api") +public class ApiController { + + @ResponseBody + @RequestMapping(value = "/menu", method = RequestMethod.GET) + public BaseResponseDTO getAll(HttpServletRequest request) throws JsonProcessingException { + String data = request.getParameter("data"); + BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); + baseResponseDTO.setData(getAll()); + ObjectMapper om = new ObjectMapper(); + System.out.println("ResponseDTO: " + om.writeValueAsString(baseResponseDTO)); + return baseResponseDTO; + } + + @ResponseBody + @RequestMapping(value = "/login") + public BaseResponseDTO login(@RequestBody Map map) throws IOException { + String username = map.get("username"); + String password = map.get("password"); + BaseResponseDTO> baseResponseDTO = new BaseResponseDTO(); + if (StringUtils.equals(username, "admin") && StringUtils.equals(password, "123456")) { + Map result = new HashMap(); + result.put("name", "admin"); + result.put("role", "ADMIN"); + result.put("uid", "1"); + baseResponseDTO.setData(result); + System.out.println(baseResponseDTO.toString()); + return baseResponseDTO; + } else { + baseResponseDTO.setCode(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.value()); + baseResponseDTO.getMessages().add(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.desc()); + return baseResponseDTO; + } + } + + @ResponseBody + @RequestMapping(value = "/logout", method = RequestMethod.GET) + public BaseResponseDTO logout(HttpServletRequest request) { + BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); + return baseResponseDTO; + } + + @ResponseBody + @RequestMapping(value = "/my", method = RequestMethod.GET) + public BaseResponseDTO my(HttpServletRequest request) { + Map map = new HashMap(); + map.put("name", "admin"); + map.put("role", "ADMIN"); + map.put("uid", "1"); + BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); + baseResponseDTO.setData(map); + return baseResponseDTO; + } + + private static Set getAll() { + MenuDTO item0 = new MenuDTO("0", "首页", "home", "Item", "/pages/home"); + + MenuDTO subMenu1 = new MenuDTO("1", "业务", "bars", "SubMenu", null); + MenuDTO item11 = new MenuDTO("11", "Mailbox", "mail", "Item", "/pages/mailbox"); + MenuDTO item12 = new MenuDTO("12", "用户列表", "user", "Item", "/pages/user"); + subMenu1.addChild(item11); + subMenu1.addChild(item12); + + MenuDTO subMenu2 = new MenuDTO("2", "Others", "coffee", "SubMenu", null); + MenuDTO itemGroup1 = new MenuDTO("21", "Group1", "windows-o", "ItemGroup", null); + MenuDTO item22 = new MenuDTO("22", "Group1-1", null, "Item", null); + MenuDTO divider = new MenuDTO("23", "Divider1", null, "Divider", null); + MenuDTO itemGroup2 = new MenuDTO("24", "Group2", "apple-o", "ItemGroup", null); + MenuDTO item25 = new MenuDTO("25", "Group2-1", null, "Item", null); + itemGroup1.addChild(item22); + itemGroup2.addChild(item25); + subMenu2.addChild(itemGroup1); + subMenu2.addChild(divider); + subMenu2.addChild(itemGroup2); + + Set menus = new TreeSet(); + menus.add(item0); + menus.add(subMenu1); + menus.add(subMenu2); + + return menus; + } +} diff --git a/demos/javaapp/src/main/java/io/github/dunwu/app/controller/HelloController.java b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/HelloController.java similarity index 95% rename from demos/javaapp/src/main/java/io/github/dunwu/app/controller/HelloController.java rename to demos/javaapp/src/main/java/io/github/dunwu/web/controller/HelloController.java index 731440f..c08dfd8 100644 --- a/demos/javaapp/src/main/java/io/github/dunwu/app/controller/HelloController.java +++ b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/HelloController.java @@ -1,4 +1,4 @@ -package io.github.dunwu.app.controller; +package io.github.dunwu.web.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/demos/javaapp/src/main/java/io/github/dunwu/app/controller/IndexController.java b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/IndexController.java similarity index 94% rename from demos/javaapp/src/main/java/io/github/dunwu/app/controller/IndexController.java rename to demos/javaapp/src/main/java/io/github/dunwu/web/controller/IndexController.java index 659f5e3..c473e77 100644 --- a/demos/javaapp/src/main/java/io/github/dunwu/app/controller/IndexController.java +++ b/demos/javaapp/src/main/java/io/github/dunwu/web/controller/IndexController.java @@ -1,7 +1,7 @@ /** * The Apache License 2.0 Copyright (c) 2016 Zhang Peng */ -package io.github.dunwu.app.controller; +package io.github.dunwu.web.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/demos/javaapp/src/main/java/io/github/dunwu/web/dto/BaseResponseDTO.java b/demos/javaapp/src/main/java/io/github/dunwu/web/dto/BaseResponseDTO.java new file mode 100644 index 0000000..cdff39f --- /dev/null +++ b/demos/javaapp/src/main/java/io/github/dunwu/web/dto/BaseResponseDTO.java @@ -0,0 +1,87 @@ +package io.github.dunwu.web.dto; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BaseResponseDTO { + + private Integer code = DEFAULT_RESPONSE_RESULT.SUCCESS.value(); + + private final List messages = new ArrayList<>(); + + private T data; + + public BaseResponseDTO() {} + + public BaseResponseDTO(T dto) { + this.data = dto; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public void addError(String error) { + this.messages.add(error); + } + + public void addErrors(String[] errors) { + this.addErrors(Arrays.asList(errors)); + } + + public void addErrors(List errorList) { + this.messages.addAll(errorList); + } + + public void removeError(String error) { + this.messages.remove(error); + } + + public List getMessages() { + return messages; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public enum DEFAULT_RESPONSE_RESULT { + SUCCESS(0, "[]"), // 成功 + AUTHEN_FAIL(-1, "认证失败"), // 认证失败 + AUTHOR_FAIL(-2, "权限不足"), // 授权不足 + PARAM_CHECK_FAIL(-3, ""), // 参数校验失败,错误信息交由业务逻辑处理 + RESOURCE_NOT_EXIST(-4, "请求资源不存在"), // 请求资源不存在 + SYSTEM_ERROR(-5, "系统错误"), + DATA_MALFORMAT(-6, "请求参数数据格式不正确"), + REQMETHOD_ERROR(-7, "请求方法不正确"), + TYPE_MISMATCH(-8, "请求参数类型不匹配"), + MISS_REQUEST_PARAM(-9, "请求参数缺失"); + + private final Integer value; + + private final String desc; + + DEFAULT_RESPONSE_RESULT(int value, String desc) { + this.value = value; + this.desc = desc; + } + + public int value() { + return value; + } + + public String desc() { + return desc; + } + } + +} diff --git a/demos/javaapp/src/main/java/io/github/dunwu/web/dto/MenuDTO.java b/demos/javaapp/src/main/java/io/github/dunwu/web/dto/MenuDTO.java new file mode 100644 index 0000000..1abec79 --- /dev/null +++ b/demos/javaapp/src/main/java/io/github/dunwu/web/dto/MenuDTO.java @@ -0,0 +1,122 @@ +package io.github.dunwu.web.dto; + +import java.util.Arrays; +import java.util.Set; +import java.util.TreeSet; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +public class MenuDTO implements Cloneable, Comparable { + + private String key; + + private String title; + + private String icon; + + private String type; + + private String url; + + private final Set children = new TreeSet(); + + public MenuDTO() {} + + public MenuDTO(String key, String title, String icon, String type, String url) { + this.key = key; + this.title = title; + this.icon = icon; + this.type = type; + this.url = url; + } + + public MenuDTO clone() throws CloneNotSupportedException { + super.clone(); + MenuDTO menuDTO = new MenuDTO(); + menuDTO.setType(type); + menuDTO.setKey(key); + menuDTO.setTitle(title); + menuDTO.setIcon(icon); + menuDTO.setUrl(url); + menuDTO.setUrl(url); + return menuDTO; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Set getChildren() { + return children; + } + + public void addChild(MenuDTO child) { + this.children.add(child); + } + + public void addChildren(Set children) { + this.children.addAll(children); + } + + public void addChildren(MenuDTO[] children) { + this.children.addAll(Arrays.asList(children)); + } + + @Override + public boolean equals(Object obj) { + boolean equals = false; + if (obj instanceof MenuDTO) { + MenuDTO menuDTO = (MenuDTO) obj; + equals = (new EqualsBuilder().append(url, menuDTO.getUrl())).isEquals(); + } + return equals; + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(url).toHashCode(); + } + + @Override + public int compareTo(MenuDTO otherMenuDTO) { + return new CompareToBuilder().append(key, otherMenuDTO.getKey()).append(url, otherMenuDTO.getUrl()) + .toComparison(); + } +} diff --git a/demos/javaapp/src/main/resources/spring/spring-servlet.xml b/demos/javaapp/src/main/resources/spring/spring-servlet.xml index 14f2556..34495cc 100644 --- a/demos/javaapp/src/main/resources/spring/spring-servlet.xml +++ b/demos/javaapp/src/main/resources/spring/spring-servlet.xml @@ -12,11 +12,19 @@ - + + + + + + + + diff --git a/demos/javaapp/src/main/webapp/META-INF/MANIFEST.MF b/demos/javaapp/src/main/webapp/META-INF/MANIFEST.MF index 9af6efd..35d58ec 100644 --- a/demos/javaapp/src/main/webapp/META-INF/MANIFEST.MF +++ b/demos/javaapp/src/main/webapp/META-INF/MANIFEST.MF @@ -1,2 +1,2 @@ Manifest-Version: 1.0 -Main-Class: io.github.dunwu.app.Main +Main-Class: io.github.dunwu.Main diff --git a/demos/javaapp/src/main/webapp/WEB-INF/web.xml b/demos/javaapp/src/main/webapp/WEB-INF/web.xml index 137c44d..eb85c98 100644 --- a/demos/javaapp/src/main/webapp/WEB-INF/web.xml +++ b/demos/javaapp/src/main/webapp/WEB-INF/web.xml @@ -39,6 +39,24 @@ REQUEST FORWARD + + + CorsFilter + io.github.dunwu.filter.CorsFilter + + headerKey + Host + + + regex + + ((http://)|(https://))?(\w*\.)*(\S)* + + + + CorsFilter + /* +