-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 35.5 KB
/
content.json
1
[{"title":"spring修改controller返回值,HandlerMethodReturnValueHandler","date":"2017-11-24T14:40:53.000Z","path":"2017/11/24/spring修改controller返回值,HandlerMethodReturnValueHandler/","text":"产景分析spring自带的ResponseBody已经很好用了,但是还是有一些特殊情况不能满足,比如修改controller中的返回值 这个需求看上去可能有点奇怪,为什么要修改controller中的返回值呢,毕竟返回值是程序员设置好的,框架为什么要去修改它呢? 其实应用场景是有的。当我们定义一套标准的传输格式的时候,比如是这样的格式{ code : 0, msg : \"请求成功\", data : {}} code代表着是否成功,msg接口调用失败后的信息,data封装返回的数据 我们定义一组java的类型可能如下public class Result{ private int code; private String msg; private Object data;} controller中的代码则如下 @ResponseBody@RequestMapping(\"/findUser\")public Result findPerson(@RequestParam(\"userId\")String userId){ Person p = userService.find(userId); //这里封装返回数据结果 Result result = new Result(); result.setCode(0); result.setMsg(\"成功\"); result.setData(p); return result;} 得到的json数据如下{ code : 0, msg : \"成功\", data : {person数据}} 很多时候,我们不想写这些通用的代码,我们只想直接返回真实的数据回去,但是得到的返回值是一样的 这个时候,就需要框架来修改返回值了 比如这个时候,我要写的代码可能就是这样了@ResponseBody@RequestMapping(\"/findUser\")public Person findPerson(@RequestParam(\"userId\")String userId){ Person p = userService.find(userId); return p;} 那么我们要怎么做才能达到这样的效果呢? 实现的三种方式最后一种方式推荐 调用一个方法返回数据 这是我之前使用的一个办法,因为没有找到别的办法,先使用了这种办法,但是后面发现有更简单的办法了 我们定义一个父类BaseController,这里面有这样一些东西protected void response(Object object){ HttpServletResponse response = HttpKit.getResponse(); response.setContentType(\"application/json;charset=UTF-8\"); PrintWriter writer = null; try { writer = response.getWriter(); //把得到的数据,包装到Resuest中返回 Result<Object> success = new Result<>(0, \"SUCCESS\", object); writer.write(JSON.toJSONString(success)); } catch (IOException e) { e.printStackTrace(); } finally { if(writer != null){ writer.close(); } }}protected void response(){ response(null);} 这里面有两个方法,就是向客户端写数据流,然后包装返回数据,返回客户端 这种方法能达到效果,但是就是需要开发人员去调用response()方法,而开发人员有的时候会忘记添加这个方法的时候,客户端就会没有返回值 尝试用动态代理/AOP,环绕通知修改返回值答案是可行的,但是返回值必须全部写Object代码如下@ResponseBody@RequestMapping(\"/findUser\")public Object findPerson(@RequestParam(\"userId\")String userId){ Person p = userService.find(userId); return p;} 切面的代码如下@Pointcut(\"@annotation(org.springframework.web.bind.annotation.RequestMapping)\")private void params(){}@Around(\"params()\")public Object doBasicProfiling(ProceedingJoinPoint pjp) { try { Object obj = pjp.proceed(); //包装返回值 return new Result<>(0,\"success\",obj); } catch (Throwable throwable) { throwable.printStackTrace(); String message = throwable.getMessage(); int errorCode; if(throwable instanceof PermissionException){ errorCode = ExceptionMappingUtil.getErrorCodeByException(PermissionException.class); }else{ errorCode = ExceptionMappingUtil.getErrorCodeByException(Throwable.class); } //包装异常返回值 return new Result<>(errorCode,message); }} 我们重点说一下为什么要返回Object,动态代理中,我们可以修改其内容,比如一个String类型的"寒冰"我可以改成"德码"返回,但是我不能把字符串类型的寒冰,改成整数类型的1,也就意味着我能修改其返回内容,而不能修改其返回类型 自定义返回值解析器这是最好的一个办法,修改SpringMvc的返回值处理器 我们可以猜测到,像Spring这样的框架,里面的实现肯定是非常灵活的,他肯定是有自己的返回值处理器,而我们能不能定义自己的返回值处理器,并且替换掉SpringMvc所原有的呢?答案是可以的 HandlerMethodReturnValueHandler实现org.springframework.web.method.support.HandlerMethodReturnValueHandler接口就行了 从名字就可以看出,这是一个方法返回值的处理器,我们看看这个接口的定义//当前处理器是否支持此方法,只有返回true时才会进入到handlerReturnValueboolean supportsReturnType(MethodParameter returnType);//处理返回值void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; 一个简单的实现(rest不可用)为什么说rest请求不可用,马上我们就知道了 代码实现我们写一段最简单的代码来实现它import org.springframework.core.MethodParameter;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.HandlerMethodReturnValueHandler;import org.springframework.web.method.support.ModelAndViewContainer;/** * @author zxj<br> * 时间 2017/11/23 19:36 * 说明 ... */public class ReturnValueHandler implements HandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { System.out.println(\"supportsReturnType被调用...\"); return true; } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { System.out.println(\"handleReturnValue被调用...\"); }} 代码配置然后写一段代码配置它到SpringMvc中import org.springframework.context.annotation.Configuration;import org.springframework.web.method.support.HandlerMethodReturnValueHandler;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import java.util.List;/** * @author zxj<br> * 时间 2017/11/23 16:51 * 说明 ... */@Configurationpublic class WebConfiguration extends WebMvcConfigurerAdapter { @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { returnValueHandlers.add(new ReturnValueHandler()); }} 报错的结果然后我们请求一个rest接口,发现是404错误,ReturnValueHandler的两个println()方法没有一个调用,也就是说,刚才的代码没有用,或者说我们配置的代码根本就没有进去,哈哈哈!其实是我们还忽略了一些东西 源码分析问题我们看一下SpringMvc的源码,看是在哪里调用这个HandlerMethodReturnValueHandler org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite源码如下 @Overridepublic void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { //查找一个可用的handler HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException(\"Unknown return value type: \" + returnType.getParameterType().getName()); } //重要:如果handler不为空,就调用handleReturnValue()方法 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);} 我们可以想像,HandlerMethodReturnValueHandler最终只会处理一次,因为不可能一个controller的请求,会解析多次返回内容,所以肯定只会调用一次的,而刚才我们自定义的HandlerMethodReturnValueHandler肯定不是此次返回的结果。 我们查看里面selectHandler(returnValue, returnType);的源码 private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null;} 通过debug可以发现,在第一次的for循环中,就得到了返回的结果,返回的handler为org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler,这个接口是用来返回视图的,然后视图解析器会去解析这个视图,如jsp,fremarker等 其实这个时候,我们就知道,为什么之前的接口会返回404了,因为我们返回的明明是rest接口的数据,而并不是一个视图接口啊 再从源码里面可以看到boolean isAsyncValue的值会影响到最终选取的结果,而刚才debug的结果中,该值是true,我们去看一下这个值是怎么计算的,再看一下源码 @Overridepublic boolean isAsyncReturnValue(Object value, MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler instanceof AsyncHandlerMethodReturnValueHandler) { if (((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) { return true; } } } return false;} if (handler instanceof AsyncHandlerMethodReturnValueHandler)看到这行代码有没有一种恍然大悟的感觉呢?原来我们要实现这个接口啊if(((AsyncHandlerMethodReturnValueHandler)handler).isAsyncReturnValue(value, returnType)) {return true;}同时这段代码又是什么意思呢?其实就是继承这个接口所实现的方法了。 AsyncHandlerMethodReturnValueHandler的源码我们仔细看一下org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler的源码 public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodReturnValueHandler { /** * Whether the given return value represents asynchronous computation. * @param returnValue the return value * @param returnType the return type * @return {@code true} if the return value is asynchronous. */ boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType);} 其实这个接口也间接的继承了之前的HandlerMethodReturnValueHandler,那实际上我们继承这个接口,实现自己的方法解析器就行了 如下import com.llc.platform.event.server.annotation.ResponseBody;import org.springframework.core.MethodParameter;import org.springframework.stereotype.Component;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;import org.springframework.web.method.support.ModelAndViewContainer;/** * @author zxj<br> * 时间 2017/11/23 16:48 * 说明 ... */public class HandlerValue implements AsyncHandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { return returnType.getMethodAnnotation(ResponseBody.class) != null; } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { System.out.println(returnValue); } @Override public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) { return returnType.getMethodAnnotation(ResponseBody.class) != null; }} ResponseBody不能用了 请注意,请注意,请注意,上面的#### RequestResponseBodyMethodProcessor的源码不信我们看一下``org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor``的部分源码```javapublic class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { ...省略其它代码 @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); }} 这里很明显,如果有SpringMvc的@ResponseBody,就会使用org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor controller返回值为void和String的情况或者当返回值为String时,就会进入org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler,我们看它的源码 @Overridepublic boolean supportsReturnType(MethodParameter returnType) { Class<?> paramType = returnType.getParameterType(); return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));} 最终的实现办法 必须实现org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler 不然会进入到别的handler中,具体查看spring的这段代码可以明白其逻辑public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException(\"Unknown return value type: \" + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);} 不能用spring的org.springframework.web.bind.annotation.ResponseBody,同样的会被其它的handler给触发 1.实现自己的自定义注解 我们根据这个注解来判断是否要进入我们自定义的handler import java.lang.annotation.*;/** * @author zxj<br> * 时间 2017/11/23 17:06 * 说明 ... */@Documented@Inherited@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface ResponseBody {} 这个注解千万不要和sprnig的ResponseBody混在一起,如果担心混淆,那就换一个名字 2.实现自己的handler 注意里面的ResponseBody,那是我们自已写的,千万不要用spring的 import com.alibaba.fastjson.JSON;import com.llc.platform.event.common.Result;import com.llc.platform.event.server.core.annotation.ResponseBody;import org.springframework.core.MethodParameter;import org.springframework.stereotype.Component;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * @author zxj<br> * 时间 2017/11/23 16:48 * 说明 ... */public class HandlerValue implements AsyncHandlerMethodReturnValueHandler { //返回true就被处理 @Override public boolean supportsReturnType(MethodParameter returnType) { return returnType.getMethodAnnotation(ResponseBody.class) != null; } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { //设置为已经完成该处理 mavContainer.setRequestHandled(true); HttpServletResponse response = (HttpServletResponse) webRequest.getNativeResponse(); response.setContentType(\"application/json;charset=UTF-8\"); PrintWriter writer = null; try { writer = response.getWriter(); //把得到的数据,包装到Resuest中返回 Result<Object> success = new Result<>(0, \"SUCCESS\", returnValue); writer.write(JSON.toJSONString(success)); } catch (IOException e) { e.printStackTrace(); } finally { if(writer != null){ writer.close(); } } } //返回true就被处理 @Override public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) { boolean r = returnType.getMethodAnnotation(ResponseBody.class) != null; return r; }} 2.配置handler spring boot的配置@Configurationpublic class WebConfiguration extends WebMvcConfigurerAdapter { @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { returnValueHandlers.add(new HandlerValue()); }} 3.编写controller测试 @ResponseBody@RequestMapping(\"/\")public void receive(){ System.out.println(\"a\");}@ResponseBody@RequestMapping(\"/String\")public String receive1(){ System.out.println(\"a\"); return \"afa\";} 经过测试,无论是int,boolean,void,String,double,都会被包装到Result的对象中,数据格式如下 { \"code\":0, \"msg\":\"SUCCESS\"} { \"code\":0, \"msg\":\"SUCCESS\", \"data\":\"string\"}","tags":[{"name":"源码","slug":"源码","permalink":"http://blog.xiaojiezhu/tags/源码/"}]},{"title":"rdd的操作","date":"2017-11-22T16:01:32.000Z","path":"2017/11/23/rdd的操作/","text":"rdd是spark数据集合的操作对象,它有很多操作方法 转化操作再次要调试的是转化操作转换出来的rdd都是惰性的,只有第一次实际操作的时候,才会具体计算 过滤出满足条件的数据filter()","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"rdd","slug":"rdd","permalink":"http://blog.xiaojiezhu/tags/rdd/"}]},{"title":"rdd的创建","date":"2017-11-21T16:18:36.000Z","path":"2017/11/22/rdd的创建/","text":"什么是rdd在学习之前,有必要介绍一下,什么是rdd spark中的rdd是一个不可变的分布式对象集合,每个rdd都会被分为多个区,这些分区运行在不同的spark集群的不同节点上,rdd里面可以包含java,python,scala的对象 rdd的操作 rdd的操作分为行动操作和转换操作,行动操作会计算rdd生成一个结果,比如读取某一行的数据,而转换操作,会生成一个新的rdd,比如我要过滤一些信息 rdd的创建是懒加载,也就是创建rdd的时候,并不会加载数据,而是真正运算rdd的时候,才会加载数据到rdd中 创建rdd的方式spark提供了两种创建rdd的方式,读取外部数据集,以及对一个rdd进行转换 传入集合创建rdd最简单的方式是直接传入一个已有集合创建rdd 这种情况很少见,spark是处理大数据应用,一般来说一台机器是放不下这么多数据的,这种情况多为开发阶段测试流程时使用。 java代码JavaRDD<String> lines = sc.parallelize(Arrays.asList(\"data1\",\"data2\")); scala代码val lines = sc.parallelize(List(\"data1\",\"data2\")); 从外部加载数据从外部加载数据是最常用的方式,可以从hive,hdfs等各种存储介质中加载,具体请看加载外部rdd数据 现在先从简单入手,先加载一个硬盘里面的文本文件吧 java代码JavaRDD<String> lines = sc.textFile(\"d:/data.txt\"); scala代码val lines = sc.textFile(\"d:/data.txt\");","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"rdd","slug":"rdd","permalink":"http://blog.xiaojiezhu/tags/rdd/"}]},{"title":"spark运行时的版本问题","date":"2017-11-19T15:00:43.000Z","path":"2017/11/19/spark运行时的版本问题/","text":"第一次运行的时候,报了这样的一个错误Exception in thread \"main\" java.lang.NoSuchMethodError: scala.Predef$.refArrayOps([Ljava/lang/Object;)Lscala/collection/mutable/ArrayOps; at org.apache.spark.util.Utils$.getCallSite(Utils.scala:1440) at org.apache.spark.SparkContext.<init>(SparkContext.scala:76) at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:58) at com.xiaojiezhu.spark.rdd.wordcount.JavaWordCount.main(JavaWordCount.java:26) 报错的位置是 很奇怪,这一行为什么要报错呢 原因是这样的spark的版本要与scala的版本一致才行,我们回头看一下spark的maven坐标 <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.10</artifactId> <version>2.2.0</version></dependency> 我们仔细看一下artifactId里面的属性,后面是带了一个版本号的2.10,这个版本号就是spark对应的scala版本,需要版本相对应才能正确运行 于是乎,我卸载了scala,在scala官网找到相应的2.10的版本重新安装,然后就好了","tags":[{"name":"spark问题","slug":"spark问题","permalink":"http://blog.xiaojiezhu/tags/spark问题/"}]},{"title":"spark的wordcount","date":"2017-11-19T12:52:49.000Z","path":"2017/11/19/spark的wordcount/","text":"基本上学习大数据的第一个应用程序,都是一个wordcount程序,也就是统计一个文本里面出现的单词次数 第一个wordcount以英文单词来演示,因为中文是以词语来切分才会有意思,如果中文切分词语,又要用到分词技术,分词并不是本文的重点,如果想要了解中文分词,请参考作者的另一篇文章hadoop的wordcount,这里面有详细的中文分词,甚至统计了斗破苍穹这本小说哪些词语出现的最多,你们猜恐怖如斯出现了多少次呢 准备一个文本文本内容如下hello worldhello janehello jiehello kangkangfuck youi am god 如果运行过程中报java.lang.NoSuchMethodError,请查看spark运行时的版本问题 注释参见普通java代码的实现,虽然其它的代码有点不一样,但是逻辑都是一样的 wordcount的java实现普通java代码的实现import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.FlatMapFunction;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import scala.Tuple2;import java.util.Arrays;import java.util.Iterator;/** * @Author 朱小杰 * 时间 2017-09-23 .22:31 * 说明 ... */public class JavaWordCount { public static void main(String[] args) { String dir = \"D:/spark/workcount/\"; SparkConf conf = new SparkConf().setMaster(\"local\").setAppName(\"wordCount\"); JavaSparkContext sc = new JavaSparkContext(conf); JavaRDD<String> input = sc.textFile(dir + \"in/text.txt\"); //切分为单词 JavaRDD<String> words = input.flatMap(new FlatMapFunction<String, String>() { @Override public Iterator<String> call(String s) throws Exception { return Arrays.asList(s.split(\" \")).iterator(); } }); //转换为键值对并计数 JavaPairRDD<String, Integer> counts = words.mapToPair(new PairFunction<String, String, Integer>() { @Override public Tuple2<String, Integer> call(String s) throws Exception { //这里每次迭代会得到一个字符串,返回的结果是reduce的key出现了多少次 return new Tuple2<>(s, 1); } }).reduceByKey(new Function2<Integer, Integer, Integer>() { //有必要说一下这个方法是做什么用的,返回值是代表着每个单词出现的总次数 @Override public Integer call(Integer x, Integer y) throws Exception { //这里的x,也就是第一个参数,是代表着单前单词总共出现了多少次,y代表着又出现了多少次,所以肯定是总数+新增次数 return x + y; } }); //保存为文本文件 counts.saveAsTextFile(dir + \"result\"); }} lambda表达式的实现普通java代码看着麻烦了一点,我们看一下lambdaimport org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.FlatMapFunction;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import scala.Tuple2;import java.util.Arrays;import java.util.Iterator;/** * @Author 朱小杰 * 时间 2017-09-23 .22:31 * 说明 ... */public class JavaWordCount { public static void main(String[] args) { String dir = \"D:/spark/workcount/\"; SparkConf conf = new SparkConf().setMaster(\"local\").setAppName(\"wordCount\"); JavaSparkContext sc = new JavaSparkContext(conf); JavaRDD<String> input = sc.textFile(dir + \"in/text.txt\"); JavaRDD<String> words = input.flatMap(s -> Arrays.asList(((String) s).split(\" \")).iterator());//java8 表达式版 JavaPairRDD<String, Integer> counts = words.mapToPair(s -> new Tuple2<>(s, 1)).reduceByKey((x, y) -> x + y); //使用java8的语法 counts.saveAsTextFile(dir + \"result\"); }} wordcount的scala实现import org.apache.spark.{SparkConf, SparkContext}/** * 朱小杰 * 时间 2017-09-24 .9:32 * 说明 ... */object ScalaWordCount { def main(args : Array[String]): Unit ={ val conf = new SparkConf().setMaster(\"local\").setAppName(\"wordcount\") val sc = new SparkContext(conf) val dir = \"G:\\\\javacode\\\\workspace\\\\spark\\\\spark-rdd\\\\src\\\\main\\\\java\\\\com\\\\xiaojiezhu\\\\spark\\\\rdd\\\\wordcount\\\\\" val input = sc.textFile(dir + \"wordcount.txt\") val words = input.flatMap(line => line.split(\" \")) val counts = words.map(word => (word,1)).reduceByKey((x,y) => x + y) counts.saveAsTextFile(dir + \"result\") }} 执行效果 在指定生成的目录会有下面几个文件 _SUCCESS文件代表着执行成功 part-00000文件里面有最终的返回内容,内容如下(jane,1)(you,1)(kangkang,1)(god,1)(am,1)(i,1)(jie,1)(hello,4)(fuck,1)(world,1) 这里面就有着每个单词分别出现了多少次,像hello就出现了4次","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"大数据","slug":"大数据","permalink":"http://blog.xiaojiezhu/tags/大数据/"}]},{"title":"在开发工具中编写spark代码","date":"2017-11-19T04:54:04.000Z","path":"2017/11/19/在开发工具中编写spark代码/","text":"我们编写spark代码时,肯定不会在shell中,我们都是在编译工具中操作的 使用MAVEN工程使用spark的API很简单,引入spark的依赖就好了<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.10</artifactId> <version>${version}</version></dependency> spark的依赖中包含了一个spark的运行环境,也就是说,可以直接在IDEA以本地模式运行,这样也方便调试,也不需要连接一个服务器上面的spark环境 初始化SparkContextspark的一切操作都是从SparkContext开始的 在java中初始化 有必要值得一提的是,下面代码中连接的local值是一个特殊值,它代表着会在本机启动一个spark的环境,如果要连接远程spark机器,则填写远程服务器地址 appName是给当前应用起一个名字,让管理员好区分是哪一个应用 import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaSparkContext;/** * @Author 朱小杰 * 时间 2017-09-23 .22:23 * 说明 使用scala代码初始化SparkContext <br> * setMaster() 设置集群url,local这个特殊值可以运行在单机线程中而无需连接集群<br> * setAppName() 设置应用的名称,使得可在集群管理器中可以找到这个应用的名称<br> */public class JavaSparkContextInit { public static void main(String[] args) { SparkConf conf = new SparkConf().setMaster(\"local\").setAppName(\"my App\"); JavaSparkContext jsc = new JavaSparkContext(conf); }} 在scala中初始化import org.apache.spark.{SparkConf, SparkContext}/** * 朱小杰 <br> * 时间 2017-09-23 .22:08<br> * 说明 使用scala代码初始化SparkContext <br> * setMaster() 设置集群url,local这个特殊值可以运行在单机线程中而无需连接集群<br> * setAppName() 设置应用的名称,使得可在集群管理器中可以找到这个应用的名称<br> */object ScalaSparkContextInit { def main(args:Array[String]): Unit ={ val conf = new SparkConf().setMaster(\"local\").setAppName(\"my app\") val sc = new SparkContext(conf) }}","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"大数据","slug":"大数据","permalink":"http://blog.xiaojiezhu/tags/大数据/"}]},{"title":"下载spark","date":"2017-11-19T03:50:29.000Z","path":"2017/11/19/下载spark/","text":"下载并使用spark 本章节仅仅是下载,并且介绍spark的目录,是普通安装模式,并不是集群模式,集群模式请参见spark集群模式安装 在官网下载spark的压缩包,或者从github中clone代码,然后自行编译。 解压出来有如下目录 bin 包含了可以和spark进行各种交互的shell example 官网提供的一些示例,可以查看并学习它的API conf spark的配置 jars 包含了spark运行的所有需要的jar包 sbin 真正启动spark的运行脚本 spark的shellspark带有交互式的shell,可以做即时的数据分析,提供了R,Python,Scala所提供的shell 为什么要有spark的shell,因为spark可以在多台计算机中并行计算,所以很多分布式计算都可以在几秒钟之内完成,哪握是那种十几个节点处理TB级别数据的计算,这种情况spark shell就很适合这种情况,因为不需要编写代码运行,可以在shell中直接处理并且查看消息,不仅仅是与本机的连接,甚至是远程spark机器的连接,包括连接spark集群 spark的日志有很多,很杂,如果想要调整日志的输出限制,则在conf目录创建一个log4j.properties文件来管理日志的设置,spark的conf目录已经有一个log4j.properties.template文件了,我们复制它修改这个文件就行了spark的shell在window运行有点问题,需要安装点东西,建议在linux环境运行,或者安装个虚拟机 python的shell运行python的shell的方式,进行spark根 目录,运行bin/pyspark,就会进入python的shell笔者对python不熟悉,所以以scala为例 spark的scala运行bin/spark-shell 得到如下界面 这就是spark的命令行了 我们尝试一个简单的行数统计统计一个文本文件有多少行,我们在spark的shell中输入如下命令var lines = sc.textFile(\"d:/spark/text.txt\");lines.count();//得到这个文件有多少行lines.first();//获取这个rdd中的第一个元素,也就是第一行 在如下的例子中,lines是一个rdd,是从本机电脑的文件中创建出来的,我们可以通过rdd进行各种运算","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"大数据","slug":"大数据","permalink":"http://blog.xiaojiezhu/tags/大数据/"}]},{"title":"spark介绍","date":"2017-11-19T02:50:13.000Z","path":"2017/11/19/spark介绍/","text":"spark系列spark是什么spark是一个通用计算框架,包含了一整套的计算模型,以及布式式集群的资源调度 spark的特点与hadoop相比,spark在内存中计算,速度比hadoop快的多,便于进行交互式操作 spark提供了python,java,scala,sql的API,并且spark还能运行在hadoop集群 spark的组件 spark core spark sql spark streaming MLlib GraphX spark core实现了spark core的基本功能,包含任务调度,内存管理,错误恢复,与存储系统的交互模块 spark sqlspark sql是spark用来操作数据结构化的程序包,通过spark sql,我们可以通过hive版本的sql来查询数据 spark streamingspark streaming是spark提供的对实时数据流计算的组件,比如网页服务吕在日志,或者用户提供的状态组成的消息队列,spark streaming提供了用来操作数据流的API,并且与RDD高度对应 MLlibspark包含了常见的机器学习算法,包括分类,回归,聚类,协同过滤等,还提供了模型评估,数据导入等额外的支持功能 GraphX这是用来操作图,比如社交网络的朋友关系图的程序库,可以进行并行的图计算,也扩展了rdd的API","tags":[{"name":"spark","slug":"spark","permalink":"http://blog.xiaojiezhu/tags/spark/"},{"name":"大数据","slug":"大数据","permalink":"http://blog.xiaojiezhu/tags/大数据/"}]},{"title":"浏览器鼠标滚轮事件","date":"2017-11-18T15:47:42.000Z","path":"2017/11/18/浏览器鼠标滚轮事件/","text":"监听浏览器的滚轮事件实现目标 监听鼠标滚轮事件 获取是向上滚动还是向下滚动 处理鼠标的连续滚动 笔者以谷歌浏览器亲试,谷歌内核的都可以火狐浏览器不行,ie浏览器也不行 1.实现鼠标滚轮事件window.onmousewheel = function(e){ console.log(e); if(e.deltaY > 0){ //向下 }else{ //向上 }} 2.获取是向上滚动还是向下滚动 这里面的deltaY是Y轴滚动的像素点,如果是正数,则是向下滚动,如果是负数,则是向下滚动 3.处理鼠标滚动的连续滚动事件 先说一下什么是鼠标的连续滚动,鼠标的滚轮每转动到相应的地方都会触发一个滚轮事件,但是如果滚动的用力,就可能会触发多次的滚动事件。也就是说操作一次鼠标滚动,很有可能会触发多次鼠标滚动的事件,这样如果要处理一些数据的事件,就不是我们想要的效果了 我们来处理掉这个事件,让它1秒钟只触发一次就行了 window.onmousewheel = function(e){ console.log(JSON.stringify(e)); if(e.deltaY > 0){ //向下 if(enableRool()){ //做点事情 } }else{ //向上 if(enableRool()){ //做点事情 } }}var roolTime = new Date().getTime();function enableRool(){ var now = new Date().getTime(); if(now - roolTime > 1000){ roolTime = now; return true; } return false;} 通过如上的代码可以看到,在enableRool()方法中,如果距离上次滚动时间小于1秒的话,是不会在触发滚轮事件的,所以也就不会造成一次操作,触发多次滚动的事件了","tags":[{"name":"js","slug":"js","permalink":"http://blog.xiaojiezhu/tags/js/"},{"name":"事件","slug":"事件","permalink":"http://blog.xiaojiezhu/tags/事件/"}]},{"title":"第一篇文章","date":"2017-11-13T02:26:00.000Z","path":"2017/11/13/writeblog/","text":"怎么写一篇博客呢你猜啊 是的,它就是这样子的: 直接量 变量 代码如下public void main(String[] args){ System.out.println(args);}","tags":[{"name":"文章标签","slug":"文章标签","permalink":"http://blog.xiaojiezhu/tags/文章标签/"}]},{"title":"Hello World","date":"2017-11-13T02:11:23.637Z","path":"2017/11/13/hello-world/","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post$ hexo new \"My New Post\" More info: Writing Run server$ hexo server More info: Server Generate static files$ hexo generate More info: Generating Deploy to remote sites$ hexo deploy More info: Deployment","tags":[]},{"title":"vue的用法","date":"2017-11-12T16:00:00.000Z","path":"2017/11/13/vue/","text":"#如何使用vue var v = new Vue({ el : \"#app\", data : {}}); <html> <head></head> <body></body></html>","tags":[{"name":"vue","slug":"vue","permalink":"http://blog.xiaojiezhu/tags/vue/"}]},{"title":"spring的factorybean","date":"2017-11-12T16:00:00.000Z","path":"2017/11/13/spring-factorybean/","text":"spring的factory是什么作用呢FactoryBean 可以让用户把任意bean注入到spring中","tags":[{"name":"spring","slug":"spring","permalink":"http://blog.xiaojiezhu/tags/spring/"}]}]