首页 文章 精选 留言 我的

精选列表

搜索[优化],共10000篇文章
优秀的个人博客,低调大师

spring api接口返回数据优化 —— 只返回需要的字段数据

概述 spring/spring boot 返回的json数据,通常包含了对象所有的字段,有时候浪费流量。例如一个接口有10个字段,而前端只需要2个字段,都返回会浪费流量。解决方案:前端在header中传递需要包含或需要排除的字段;后端在返回数据前进行统一拦截,只返回需要的字段。具有有多种实现方式(这里只提供spring boot)。 首先约定返回的BaseResult对象格式如下,里面result属性就是实际各种数据对象。 { "ret":0, "msg":null, "result":{ "id":1, "name":"后摄像头53" }, "time":1540972430498 } 实现方式一:通过AOP controller来实现 aop实现步骤说明: 判断返回的是不是BaseResult对象 判断request header或params是否有x-include-fields、x-exclude-fields属性(有则取出来放入set中) 满足以上条件则对BaseResult.result 对象进行处理,用Map替换result对象,Map只返回需要的字段。如果是Array或Collection则每个Item替换成一个Map。 import com.cehome.cloudbox.common.object.BaseResult; import com.cehome.cloudbox.common.object.ItemsResult; import com.cehome.cloudbox.common.object.PageResult; import com.cehome.cloudbox.common.page.Page; import com.cehomex.spring.feign.FeignRequestHolder; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.beans.PropertyDescriptor; import java.util.*; @Aspect public class ControllerAOP { private static String INCLUDE_FIELDS = "x-include-fields"; private static String EXCLUDE_FIELDS = "x-exclude-fields"; private static String P_INCLUDE_FIELDS = "x-include-fields"; private static String P_EXCLUDE_FIELDS = "x-exclude-fields"; private static final Logger logger = LoggerFactory.getLogger(ControllerAOP.class); @Pointcut("within(@org.springframework.stereotype.Controller *)") public void controller() { } @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)") public void restController() { } @Around("(controller() || restController()) && execution(public * *(..))") public Object proceed(ProceedingJoinPoint joinPoint) throws Throwable { try { Object object=joinPoint.proceed(); ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); if (requestAttributes != null) { HttpServletRequest request = requestAttributes.getRequest(); handleReturnValue(object,request); } return object; } finally { FeignRequestHolder.removeAll(); } } /** * 返回前端需要的字段 * @param o * @param request * @throws Exception */ public void handleReturnValue(Object o,HttpServletRequest request) throws Exception { if(!isSuccess(o)) return; //HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class); //HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class); String fields1 = StringUtils.trimToEmpty(request.getHeader(INCLUDE_FIELDS)); if(fields1.length()==0) fields1 = StringUtils.trimToEmpty(request.getParameter(P_INCLUDE_FIELDS)); String fields2 = StringUtils.trimToEmpty(request.getHeader(EXCLUDE_FIELDS)); if(fields2.length()==0) fields2 = StringUtils.trimToEmpty(request.getParameter(P_EXCLUDE_FIELDS)); if (fields1.length() > 0 || fields2.length() > 0) { Set<String> includes = fields1.length() == 0 ? new HashSet<>() : new HashSet<>(Arrays.asList(fields1.split(","))); Set<String> excludes = fields2.length() == 0 ? new HashSet<>() : new HashSet<>(Arrays.asList(fields2.split(","))); if (o instanceof BaseResult) { BaseResult result = (BaseResult) o; Object object = result.getResult(); result.setResult(convertResult(object, includes, excludes)); } else if (o instanceof ItemsResult) { ItemsResult result = (ItemsResult) o; Object object = result.getItems(); result.setItems(convertResult(object, includes, excludes)); } else if (o instanceof PageResult) { PageResult result = (PageResult) o; Object object = result.getPage(); if (object instanceof Page) { Page page=(Page) object; List datas = page.getDatas(); page.setDatas((List)convertResult(datas, includes, excludes)); } } } } private boolean isSuccess(Object object){ if(object==null) return false; if (object instanceof BaseResult) return ( (BaseResult) object).isSuccess(); if (object instanceof ItemsResult) return ( (ItemsResult) object).isSuccess(); if (object instanceof PageResult) return ( (PageResult) object).isSuccess(); return false; } /*private void handleObject(Object object, Set<String> includes, Set<String> excludes) throws Exception { PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(object); for (PropertyDescriptor pd : pds) { String name = pd.getName(); if (name.equals("class")) { continue; } if (excludes.contains(name) || !includes.contains(name)) { PropertyUtils.setProperty(object, name, null); } } }*/ /** * convert objects to maps * @param object * @param includes * @param excludes * @return * @throws Exception */ private Object convertResult(Object object, Set<String> includes, Set<String> excludes) throws Exception{ if (object instanceof Object[]) { Object[] objects = (Object[]) object; return convertArray(objects,includes,excludes); } else if (object instanceof Collection) { Collection collection = (Collection) object; return convertCollection(collection,includes,excludes); }else{ return convertObject(object,includes,excludes); } } private Collection<Map> convertCollection(Collection collection, Set<String> includes, Set<String> excludes) throws Exception{ Collection<Map> result=new ArrayList<>(); for (Object item : collection) { result.add(convertObject(item,includes,excludes)); } return result; } private Map[] convertArray(Object[] objects, Set<String> includes, Set<String> excludes) throws Exception{ Map[] result=new HashMap[objects.length]; for(int i=0;i<objects.length;i++){ result[i]=convertObject(objects[i],includes,excludes); } return result; } /** * convert object to map * @param object input * @param includes include props * @param excludes exclude props * @return * @throws Exception */ private Map convertObject(Object object, Set<String> includes, Set<String> excludes) throws Exception { Map<Object,Object> result=new HashMap<>(); if(!(object instanceof Map)) { PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(object); for (PropertyDescriptor pd : pds) { String name = pd.getName(); if (name.equals("class")) { continue; } if(!excludes.isEmpty() && excludes.contains(name)){ continue; } if(!includes.isEmpty() && !includes.contains(name)){ continue; } result.put(name,PropertyUtils.getProperty(object, name)); } }else { Map<Object,Object> map=(Map<Object,Object>) object; for(Map.Entry<Object,Object> entry :map.entrySet()){ String name= entry.getKey()==null?"":entry.getKey().toString(); if(!excludes.isEmpty() && excludes.contains(name)){ continue; } if(!includes.isEmpty() && !includes.contains(name)){ continue; } result.put(entry.getKey(),entry.getValue()); } } return result; } } 用Map替换的方式改变了原来的对象,还有一种效率更好的不改变对象的方式,就是把不需要返回的字段设为null,然后配置一个JSON处理bean,统一过滤null的字段。这种方式null的字段就不再返回前端,需要前端做些兼容。 @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return objectMapper; } 实现方式二:自定义HttpMessageConverter来实现 spring boot缺省包含了好几个消息转换器,根据返回媒体类型进行匹配,第一个匹配上就忽略掉其它的了。MappingJackson2HttpMessageConverter 是其处理JSON的消息转换器。 所以,需要先删除缺省的MappingJackson2HttpMessageConverter 继承MappingJackson2HttpMessageConverter,实现自定义的消息转换。 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { //-- 移除缺省的JSON处理器 for (int i = converters.size() - 1; i >= 0; i--) { HttpMessageConverter<?> messageConverter = converters.get(i); if (messageConverter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) converters.remove(i); } // -- 添加自己得JSON处理器 MappingJackson2HttpMessageConverter c = new MappingJackson2HttpMessageConverter() { @Override protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { //-- 例子一: 转成fastjson对象,然后替换name字段 JSONObject json = (JSONObject) JSON.toJSON(object); json.getJSONObject("result").put("name", "coolma"); super.writeInternal(json, type, outputMessage); //-- 例子二: 用过滤器只保留name字段,其它字段不要。 //注意,例子二需要给BaseResult对象的result属性加上com.fasterxml.jackson.annotation.JsonFilter注解: // @JsonFilter("result") // private T result; MappingJacksonValue value = new MappingJacksonValue(object); value.setFilters(new SimpleFilterProvider().addFilter("result", SimpleBeanPropertyFilter.filterOutAllExcept("name"))); super.writeInternal(value, type, outputMessage); } }; c.setDefaultCharset(Charset.forName("UTF-8")); List<MediaType> mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); c.setSupportedMediaTypes(mediaTypes); converters.add(c); } }

优秀的个人博客,低调大师

使用C#创建windows服务续之使用Topshelf优化Windows服务

前言: 之前写了一篇“使用C#创建windows服务”,https://www.cnblogs.com/huangwei1992/p/9693167.html,然后有博友给我推荐了一个开源框架Topshelf。 写了一点测试代码,发现Topshelf框架确实在创建windows服务上非常好用,于是就对我之前的代码进行了改造。 开发流程: 1.在不使用Topshelf框架的情况下,我们需要创建Windows服务程序,在这里我们只需要创建一个控制台程序就行了 2.添加引用 使用程序安装命令: Install-Package Topshelf 直接在NuGet包管理器中搜索Topshelf,点击安装即可: 3.新建核心类CloudImageManager 主要方法有三个:LoadCloudImage、Start、Stop,直接贴代码 /// <summary> /// 功能描述 :卫星云图下载管理器 /// 创 建 者 :Administrator /// 创建日期 :2018/9/25 14:29:03 /// 最后修改者 :Administrator /// 最后修改日期:2018/9/25 14:29:03 /// </summary> public class CloudImageManager { private string _ImagePath = System.Configuration.ConfigurationManager.AppSettings["Path"]; private Timer _Timer = null; private double Interval = double.Parse(System.Configuration.ConfigurationManager.AppSettings["Minutes"]); public CloudImageManager() { _Timer = new Timer(); _Timer.Interval = Interval * 60 * 1000; _Timer.Elapsed += _Timer_Elapsed; } void _Timer_Elapsed(object sender, ElapsedEventArgs e) { StartLoad(); } /// <summary> /// 开始下载云图 /// </summary> private void StartLoad() { LoadCloudImage(); } public void Start() { StartLoad(); _Timer.Start(); } public void Stop() { _Timer.Stop(); } /// <summary> /// 下载当天所有卫星云图 /// </summary> private void LoadCloudImage() { CreateFilePath();//判断文件夹是否存在,不存在则创建 //获取前一天日期 string lastYear = DateTime.Now.AddDays(-1).Year.ToString(); string lastMonth = DateTime.Now.AddDays(-1).Month.ToString(); if (lastMonth.Length < 2) lastMonth = "0" + lastMonth; string lastDay = DateTime.Now.AddDays(-1).Day.ToString(); if (lastDay.Length < 2) lastDay = "0" + lastDay; //获取当天日期 string year = DateTime.Now.Year.ToString(); string month = DateTime.Now.Month.ToString(); if (month.Length < 2) month = "0" + month; string day = DateTime.Now.Day.ToString(); if (day.Length < 2) day = "0" + day; //设置所有文件名 string[] dates0 = { lastYear + "/" + lastMonth + "/" + lastDay, year + "/" + month + "/" + day }; string[] dates = { lastYear + lastMonth + lastDay, year + month + day }; string[] hours = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" }; string[] minutes = { "15", "45" }; int hLength = hours.Count(); //遍历下载当天所有在线云图 for (int i = 0; i < 2; i++) { string date = dates[i]; string date0 = dates0[i]; for (int j = 0; j < hLength; j++) { string hour = hours[j]; for (int k = 0; k < 2; k++) { string minute = minutes[k]; string imageUrl = @"http://image.nmc.cn/product/" + date0 + @"/WXCL/SEVP_NSMC_WXCL_ASC_E99_ACHN_LNO_PY_" + date + hour + minute + "00000.JPG"; string[] s = imageUrl.Split('/'); string imageName = s[s.Count() - 1]; HttpWebRequest request = HttpWebRequest.Create(imageUrl) as HttpWebRequest; HttpWebResponse response = null; try { response = request.GetResponse() as HttpWebResponse; } catch (Exception) { continue; } if (response.StatusCode != HttpStatusCode.OK) continue; Stream reader = response.GetResponseStream(); FileStream writer = new FileStream(_ImagePath + imageName, FileMode.OpenOrCreate, FileAccess.Write); byte[] buff = new byte[512]; int c = 0; //实际读取的字节数 while ((c = reader.Read(buff, 0, buff.Length)) > 0) { writer.Write(buff, 0, c); } writer.Close(); writer.Dispose(); reader.Close(); reader.Dispose(); response.Close(); } } } } /// <summary> /// 判断文件夹是否存在,不存在则创建 /// </summary> private void CreateFilePath() { if (Directory.Exists(_ImagePath)) { ClearImages(); return; } else { Directory.CreateDirectory(_ImagePath); } } /// <summary> /// 清空文件夹下所有文件 /// </summary> private void ClearImages() { try { DirectoryInfo dir = new DirectoryInfo(_ImagePath); FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //返回目录中所有文件和子目录 foreach (FileSystemInfo i in fileinfo) { if (i is DirectoryInfo) //判断是否文件夹 { DirectoryInfo subdir = new DirectoryInfo(i.FullName); subdir.Delete(true); //删除子目录和文件 } else { File.Delete(i.FullName); //删除指定文件 } } } catch (Exception e) { Console.WriteLine(e.Message); } } } 然后在Program.cs中调用: static void Main(string[] args) { HostFactory.Run(x => //1 { x.Service<CloudImageManager>(s => //2 { s.ConstructUsing(name => new CloudImageManager()); //3 s.WhenStarted(tc => tc.Start()); //4 s.WhenStopped(tc => tc.Stop()); //5 }); x.RunAsLocalSystem(); //6 x.SetDescription("卫星云图实时下载工具"); //7 x.SetDisplayName("CloudImageLoad"); //8 x.SetServiceName("CloudImageLoad"); //9 }); } 可以看到调用的时候主要涉及到CloudImageManager类中的构造函数、Start方法以及Stop方法 安装、运行和卸载: 在Topshelf框架下进行服务的这些操作相对而言就简单多了 安装:Topshelf.CloudImageLoad.exe install 启动:Topshelf.CloudImageLoad.exe start 卸载:Topshelf.CloudImageLoad.exe uninstall 操作界面如下:(注意:必须用管理员身份运行命令提示符) 在这里只贴出了安装命令的截图,其他命令相信就不用多说了。 查看服务列表,这时我们的服务就已经安装成功了 参考链接: http://www.cnblogs.com/jys509/p/4614975.html

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册