1.新建CSS和JS文件2.新建静态资源配置类:ImsConfig.javapackagecn.coralcloud.ims.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/***@authorc-geff*@nameImsConfig*@description*@date2020-11-0315:28*/@ConfigurationpublicclassImsConfigextendsWebMvcConfigurerAdapter{@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");super.addResourceHandlers(registry);}}注:新建config包,然后新建ImsConfig类,继承自WebMvcConfigurerAdapter,实现了addResourceHandlers方法,该方法设置了访问/static/路径的文件时会映射到项目static文件夹下3.login.ftl修改,head添加CSS引入:4.login.ftl修改,页面布局修改:5.编写对应的main.css文件,该文件为通用样式html,body{padding:0;margin:0;}.ims-form-label{font-size:15px;color:rgba(0,0,0,.7);width:100px;height:40px;line-height:40px;letter-spacing:3px;}.ims-form-input{height:40px;line-height:40px;flex:1;outline:0;padding:015px;border:1pxsolid#DCDFE6;border-radius:4px;}.ims-form-input:focus{border-color:#409EFF;}.ims-form-item{margin:15px0;width:100%;display:flex;}.ims-button{height:40px;line-height:40px;border-radius:4px;padding:030px;border:none;color:#FFFFFF;font-size:14px;background-color:#409EFF;cursor:pointer;margin:15px0;outline:0;}.ims-button:hover{background-color:#3888e0;}.ims-button:focus{background-color:rgba(64,158,255,0.81);}6.编写对应的login.css文件,该文件为登录页专用样式.login-container{display:flex;align-content:center;justify-content:center;text-align:center;-webkit-box-pack:center;-webkit-box-align:center;align-items:center;width:100vw;height:100vh;background-image:url("/static/images/login_bg.jpg");background-repeat:no-repeat;background-size:100%100%;}.login-containerform{width:350px;height:300px;background-color:rgba(255,255,255,.7);border-radius:5px;padding:10px20px;}.login-container.ims-button{width:100%}.errormsg{color:#ed2322;font-size:13px;margin-bottom:0;}7.static目录下新建文件夹images保存背景图片login_bg.jpglogin_bg.jpg
FastDFS服务器迁移1.1目标服务器安装FastDFS首先按照上一篇文章《FastDFS介绍和安装》搭建好新的FastDFS服务器(Tracker,Storage),先配置好不用启动1.2修改配置文件修改新的Storage配置文件/etc/fdfs/storage.conf将tracker_server的IP修改为旧的Tracker服务器IP1.3启动目标Storage进程,同步数据servicefdfs_storagedrestart查看同步进程,在旧tracker服务器执行:fdfs_monitor/etc/fdfs/client.conf可以看到同步状态:等待数据同步...ACTIVE标识表示数据已经同步完成数据同步完成后,停掉Storage服务servicefdfs_storagedstop1.4修改storage配置文件修改/etc/fdfs/storage.conf文件将tracker_server的IP修改为新的tracker服务器IP1.5修改.data_init_flag文件该文件所在位置为storage.conf文件中所配置的base_path路径后面的data路径下,如配置为/home/data/fastdfs/storage,则文件所在位置为/home/data/fastdfs/storage/data/下将文件中sync_src_server配置项留空,其它配置项不变sync_src_server=1.6启动进程启动新的storage服务器进程,启动新的tracker服务器进程,在新tracker服务器下fdfs_monitor/etc/fdfs/client.conf查看Storage状态
1.@Component,@Service,@Controller,@Repository是spring注解,注解后可以被spring框架所扫描并注入到spring容器来进行管理2.@Component是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能3.如果想使用自定义的组件注解,那么只要在你定义的新注解中加上@Component即可:4.@Repository注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能。5.@Controller层是spring-mvc的注解,具有将请求进行转发,重定向的功能。6.@Service层是业务逻辑层注解,这个注解只是标注该类处于业务逻辑层。7.用这些注解对应用进行分层之后,就能将请求处理,义务逻辑处理,数据库操作处理分离出来,为代码解耦,也方便了以后项目的维护和开发。
1.验证码工具类1.新建包utils2.新建VerifyCodeUtil类packagecn.coralcloud.ims.utils;importjavax.imageio.ImageIO;importjava.awt.*;importjava.awt.geom.AffineTransform;importjava.awt.image.BufferedImage;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.OutputStream;importjava.util.Arrays;importjava.util.Random;/***@authorc-geff*/publicclassVerifyCodeUtil{/***使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符*/privatestaticfinalStringVERIFY_CODES="23456789ABCDEFGHJKLMNPQRSTUVWXYZ";privatestaticRandomrandom=newRandom();/***使用系统默认字符源生成验证码*@paramverifySize验证码长度*@return*/publicstaticStringgenerateVerifyCode(intverifySize){returngenerateVerifyCode(verifySize,VERIFY_CODES);}/***使用指定源生成验证码*@paramverifySize验证码长度*@paramsources验证码字符源*@return*/publicstaticStringgenerateVerifyCode(intverifySize,Stringsources){if(sources==null||sources.length()==0){sources=VERIFY_CODES;}intcodesLen=sources.length();Randomrand=newRandom(System.currentTimeMillis());StringBuilderverifyCode=newStringBuilder(verifySize);for(inti=0;i<verifySize;i++){verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));}returnverifyCode.toString();}/***生成随机验证码文件,并返回验证码值*@paramw*@paramh*@paramoutputFile*@paramverifySize*@return*@throwsIOException*/publicstaticStringoutputVerifyImage(intw,inth,FileoutputFile,intverifySize)throwsIOException{StringverifyCode=generateVerifyCode(verifySize);outputImage(w,h,outputFile,verifyCode);returnverifyCode;}/***输出随机验证码图片流,并返回验证码值*@paramw*@paramh*@paramos*@paramverifySize*@return*@throwsIOException*/publicstaticStringoutputVerifyImage(intw,inth,OutputStreamos,intverifySize)throwsIOException{StringverifyCode=generateVerifyCode(verifySize);outputImage(w,h,os,verifyCode);returnverifyCode;}/***生成指定验证码图像文件*@paramw*@paramh*@paramoutputFile*@paramcode*@throwsIOException*/publicstaticvoidoutputImage(intw,inth,FileoutputFile,Stringcode)throwsIOException{if(outputFile==null){return;}Filedir=outputFile.getParentFile();if(!dir.exists()){dir.mkdirs();}try{outputFile.createNewFile();FileOutputStreamfos=newFileOutputStream(outputFile);outputImage(w,h,fos,code);fos.close();}catch(IOExceptione){throwe;}}/***输出指定验证码图片流*@paramw*@paramh*@paramos*@paramcode*@throwsIOException*/publicstaticvoidoutputImage(intw,inth,OutputStreamos,Stringcode)throwsIOException{intverifySize=code.length();BufferedImageimage=newBufferedImage(w,h,BufferedImage.TYPE_INT_RGB);Randomrand=newRandom();Graphics2Dg2=image.createGraphics();g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);Color[]colors=newColor[5];Color[]colorSpaces=newColor[]{Color.WHITE,Color.CYAN,Color.GRAY,Color.LIGHT_GRAY,Color.MAGENTA,Color.ORANGE,Color.PINK,Color.YELLOW};float[]fractions=newfloat[colors.length];for(inti=0;i<colors.length;i++){colors[i]=colorSpaces[rand.nextInt(colorSpaces.length)];fractions[i]=rand.nextFloat();}Arrays.sort(fractions);//设置边框色g2.setColor(Color.GRAY);g2.fillRect(0,0,w,h);Colorc=getRandColor(200,250);//设置背景色g2.setColor(c);g2.fillRect(0,2,w,h-4);//绘制干扰线Randomrandom=newRandom();//设置线条的颜色g2.setColor(getRandColor(160,200));intloop=20;for(inti=0;i<loop;i++){intx=random.nextInt(w-1);inty=random.nextInt(h-1);intxl=random.nextInt(6)+1;intyl=random.nextInt(12)+1;g2.drawLine(x,y,x+xl+40,y+yl+20);}//添加噪点//噪声率floatyawpRate=0.05f;intarea=(int)(yawpRate*w*h);for(inti=0;i<area;i++){intx=random.nextInt(w);inty=random.nextInt(h);intrgb=getRandomIntColor();image.setRGB(x,y,rgb);}//使图片扭曲shear(g2,w,h,c);g2.setColor(getRandColor(100,160));intfontSize=h-4;Fontfont=newFont("Algerian",Font.ITALIC,fontSize);g2.setFont(font);char[]chars=code.toCharArray();for(inti=0;i<verifySize;i++){AffineTransformaffine=newAffineTransform();affine.setToRotation(Math.PI/4*rand.nextDouble()*(rand.nextBoolean()?1:-1),(w/verifySize)*i+fontSize/2,h/2);g2.setTransform(affine);g2.drawChars(chars,i,1,((w-10)/verifySize)*i+5,h/2+fontSize/2-10);}g2.dispose();ImageIO.write(image,"jpg",os);}privatestaticfinalIntegerCOLOR_MAX_INT=255;privatestaticColorgetRandColor(intfc,intbc){if(fc>COLOR_MAX_INT){fc=COLOR_MAX_INT;}if(bc>COLOR_MAX_INT){bc=COLOR_MAX_INT;}intr=fc+random.nextInt(bc-fc);intg=fc+random.nextInt(bc-fc);intb=fc+random.nextInt(bc-fc);returnnewColor(r,g,b);}privatestaticintgetRandomIntColor(){int[]rgb=getRandomRgb();intcolor=0;for(intc:rgb){color=color<<8;color=color|c;}returncolor;}privatestaticint[]getRandomRgb(){int[]rgb=newint[3];intloop=3;for(inti=0;i<loop;i++){rgb[i]=random.nextInt(255);}returnrgb;}privatestaticvoidshear(Graphicsg,intw1,inth1,Colorcolor){shearx(g,w1,h1,color);sheary(g,w1,h1,color);}privatestaticvoidshearx(Graphicsg,intw1,inth1,Colorcolor){intperiod=random.nextInt(2);booleanborderGap=true;intframes=1;intphase=random.nextInt(2);for(inti=0;i<h1;i++){doubled=(double)(period>>1)*Math.sin((double)i/(double)period+(6.2831853071795862D*(double)phase)/(double)frames);g.copyArea(0,i,w1,1,(int)d,0);if(borderGap){g.setColor(color);g.drawLine((int)d,i,0,i);g.drawLine((int)d+w1,i,w1,i);}}}privatestaticvoidsheary(Graphicsg,intw1,inth1,Colorcolor){intperiod=random.nextInt(40)+10;booleanborderGap=true;intframes=20;intphase=7;for(inti=0;i<w1;i++){doubled=(double)(period>>1)*Math.sin((double)i/(double)period+(6.2831853071795862D*(double)phase)/(double)frames);g.copyArea(i,0,1,h1,0,(int)d);if(borderGap){g.setColor(color);g.drawLine(i,(int)d,i,0);g.drawLine(i,(int)d+h1,i,h1);}}}}2.UserController新增验证码接口2.1新增captcha方法@GetMapping("/captcha")publicvoidcaptcha(HttpServletResponseresponse,HttpSessionsession){Stringcode=VerifyCodeUtil.generateVerifyCode(4);session.setAttribute(SessionKey.ADMIN_CAPTCHA_KEY,code);try{VerifyCodeUtil.outputImage(150,50,response.getOutputStream(),code);}catch(IOExceptione){e.printStackTrace();}}2.2修改login方法,增加验证下方为最终的登录验证方法:@PostMapping("/login")publicModelAndViewlogin(Stringemail,Stringpassword,Stringcaptcha,HttpSessionsession){StringsessionCaptcha=(String)session.getAttribute(SessionKey.ADMIN_CAPTCHA_KEY);ModelAndViewview=newModelAndView();view.setViewName("user/login");//将email和password写回到页面,使得登录失败时输入的账号密码不会丢失view.addObject("email",email);view.addObject("password",password);if(StringUtils.isEmpty(captcha)||!Objects.equals(captcha,sessionCaptcha)){view.addObject("errmsg","验证码错误!");returnview;}Useruser=userService.login(email,password);if(user!=null){session.setAttribute(SessionKey.ADMIN_USER_KEY,user);view.setViewName("redirect:/index");returnview;}view.addObject("errmsg","用户名或密码错误!");returnview;}注:此处将Session的Key值通过一个常量类SessionKey保存2.3SessionKey类在utils包下新建SessionKey类packagecn.coralcloud.ims.utils;/***@authorc-geff*@nameSessionKey*@description*@date2020-11-0410:12*/publicclassSessionKey{publicstaticfinalStringADMIN_USER_KEY="AdminUserKey";publicstaticfinalStringADMIN_CAPTCHA_KEY="AdminLoginCaptchaCode";}3.修改login.ftl3.1引入jquery下载jqeury文件jquery.min.js在/static/js文件夹下新建jquery文件夹,将jquery.min.js复制到文件夹下修改login.ftl文件,最终login.ftl内容为下:<!doctypehtml><htmllang="en"xmlns:th="http://www.thymeleaf.org"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><linktype="text/css"rel="stylesheet"href="/static/css/main.css"><linktype="text/css"rel="stylesheet"href="/static/css/login.css"><scriptsrc="/static/js/jquery/jquery.min.js"type="application/javascript"></script><title>用户登录</title></head><body><divclass="login-container"><formaction="/user/login"method="post"><div><h3>用户登录</h3></div><divclass="ims-form-item"><labelclass="ims-form-label"for="email">登录邮箱</label><inputclass="ims-form-input"id="email"autocomplete="off"th:value="${email}"placeholder="请输入邮箱"type="text"name="email"></div><divclass="ims-form-item"><labelclass="ims-form-label"for="password">登录密码</label><inputclass="ims-form-input"id="password"autocomplete="new-password"th:value="${password}"placeholder="请输入密码"type="password"name="password"></div><divclass="ims-form-item"><labelclass="ims-form-label"for="captcha">图片验证</label><inputclass="ims-form-input"id="captcha"type="text"placeholder="请输入图片验证码"name="captcha"><imgsrc="/user/captcha"class="captcha"alt="图片验证码"></div><pclass="errormsg"th:if="${errmsg}!=null"th:text="${errmsg}"></p><div><buttontype="submit"class="ims-button">登录</button></div></form></div></body><scripttype="application/javascript">$(document).ready(function(){$('img.captcha').click(function(){$(this).attr("src","/user/captcha?_="+newDate().getTime())})})</script></html>注,login.ftl变更如下:1.head新增引入jquery.min.js2.input新增读取前面保存的email和password3.新增图片验证码输入框及图片4.新建图片点击监听事件,更换图片验证码4.修改样式login.css#captcha{width:100px;border-top-right-radius:0;border-bottom-right-radius:0;}.captcha{width:1px;flex:1;height:42px;cursor:pointer;border-top-right-radius:4px;border-bottom-right-radius:4px;}5.最终效果
1.新建数据库表ims-learn.user2.Model包下新建User类注:因为之前初始化项目时添加了lombok依赖,所以model类可以不用写setter/getter,直接使用@Data注解替代3.编写UserDao接口类4.UserMapper.xml<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="cn.coralcloud.ims.dao.UserDao"><resultMapid="userResultMap"type="User"><idproperty="id"column="id"/><resultproperty="createTime"column="create_time"/><resultproperty="updateTime"column="update_time"/></resultMap><selectid="login"resultMap="userResultMap">select*fromuserwhereemail=#{email}andpassword=#{password}</select></mapper>5.mybatis.xml编写mybatis基础配置,新建resources/mybatis/mybatis.xml<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTDConfig3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><settingname="logImpl"value="STDOUT_LOGGING"/><settingname="lazyLoadingEnabled"value="true"/><settingname="aggressiveLazyLoading"value="false"/><settingname="lazyLoadTriggerMethods"value=""/></settings></configuration>6.UserService.java7.UserController.javapackagecn.coralcloud.ims.controller;importcn.coralcloud.ims.model.User;importcn.coralcloud.ims.service.UserService;importcom.sun.org.apache.xpath.internal.operations.Mod;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.ui.Model;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.View;importjavax.servlet.http.HttpSession;/***@authorc-geff*@nameUserController*@description*@date2020-11-0310:45*/@Controller@RequestMapping("/user")publicclassUserController{@AutowiredprivateUserServiceuserService;@PostMapping("/login")publicModelAndViewlogin(Stringemail,Stringpassword,HttpSessionsession){ModelAndViewview=newModelAndView();view.setViewName("user/login");Useruser=userService.login(email,password);if(user!=null){session.setAttribute("AdminUserKey",user);view.setViewName("redirect:/index");returnview;}view.addObject("errmsg","用户名或密码错误!");returnview;}@GetMapping("/login")publicStringlogin(){return"user/login";}}8.login.ftl9.IndexController改造10.index.ftl改造,展示用户登录后的用户名11.数据库添加一条用户数据,然后在/user/login页面登录测试
采集节点主要安装Filebeat组件即可,Filebeat可以很简单运行在Windows/Linux操作系统上,不需要其余环境。下载Filebeat压缩包:https://www.elastic.co/downloads/past-releases/filebeat-6-2-4根据操作系统选择对应的版本下载解压修改目录下filebeat.yml文件,具体配置下图:上图为filebeat的输入端配置,指定监听文件上图为filebeat的输出端配置,指定输出到本机的Logstash中Filebeat启动(cd$FILEBEAT_HOME):./filebeat-e-cfilebeat.yml后台启动可使用nohup命令nohup./filebeat-e-cfilebeat.yml-d"publish">logs/filebeat.log2>&1&
1.在使用mybatis的动态sql时,有时候遇到根据条件判断添加where后面的筛选条件的情况,会出现多余的AND或者OR:2.使用where关键字:2.1当第一个参数为空时,拼接后的sql为:select*fromtdwhereandphone=.......;2.2当所有的参数都为空时,拼接后的sql为:select*fromtdwhere.....,显然这样的sql不是完整的sql,执行时会报错.3.使用where标签时:3.1当第一个参数为空时,拼接后的sql为:select*fromtdwherephone=......(若语句的开头为AND或者OR时,where元素会将他们去除).3.2当所有的参数都为空时,拼接后的sql为:select*fromtd.(where元素只会在至少有一个子元素的条件返回SQL子句的情况下才去插入“WHERE”子句)。
Vue+SpringBoot实现WebSocket通信服务端在SpringBoot项目中添加ServerEndpointExporterBean的方法@BeanpublicServerEndpointExporterexporter(){returnnewServerEndpointExporter();}创建WebSocket客户端管理类:WebSocketComponent.javapackagecn.coralcloud.blog.web.component;importcom.alibaba.fastjson.JSON;importorg.springframework.stereotype.Component;importjavax.websocket.*;importjavax.websocket.server.ServerEndpoint;importjava.io.IOException;importjava.util.Objects;importjava.util.concurrent.CopyOnWriteArraySet;/**@authorgeff@nameWebSocketComponent@description@date2019-12-1814:22/@ServerEndpoint(value="/websocket")@ComponentpublicclassWebSocketComponent{/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。/privatestaticintonlineCount=0;/**concurrent包的线程安全Set,用来存放每个客户端对应的CumWebSocket对象。/privatestaticCopyOnWriteArraySetwebSocketSet=newCopyOnWriteArraySet<>();/**与某个客户端的连接会话,需要通过它来给客户端发送数据/privateSessionsession;/**连接建立成功调用的方法@paramsessionsession/@OnOpenpublicvoidonOpen(Sessionsession){this.session=session;//加入set中webSocketSet.add(this);//添加在线人数addOnlineCount();System.out.println("新连接接入。当前在线人数为:"+getOnlineCount());}/**连接关闭调用的方法/@OnClosepublicvoidonClose(){//从set中删除webSocketSet.remove(this);//在线数减1subOnlineCount();System.out.println("有连接关闭。当前在线人数为:"+getOnlineCount());}/**收到客户端消息后调用@parammessagemessage@paramsessionsession/@OnMessagepublicvoidonMessage(Stringmessage,Sessionsession){System.out.println("客户端发送的消息:"+message);sendAll(JSON.toJSONString(messageDTO),session.getId());}/**群发@parammessagemessage/privatestaticvoidsendAll(Stringmessage,StringsessionId){webSocketSet.forEach(item->{if(!item.session.getId().equals(sessionId)){//群发try{item.sendMessage(message);}catch(IOExceptione){e.printStackTrace();}}});}/**发生错误时调用@paramsessionsession@paramerrorerror/@OnErrorpublicvoidonError(Sessionsession,Throwableerror){System.out.println("----websocket-------有异常啦");error.printStackTrace();}/**减少在线人数/privatevoidsubOnlineCount(){WebSocketComponent.onlineCount--;}/**添加在线人数/privatevoidaddOnlineCount(){WebSocketComponent.onlineCount++;}/**当前在线人数@returnint/publicstaticsynchronizedintgetOnlineCount(){returnonlineCount;}/**发送信息@parammessagemessagethrowsIOException/publicvoidsendMessage(Stringmessage)throwsIOException{//获取session远程基本连接发送文本消息this.session.getBasicRemote().sendText(message);//this.session.getAsyncRemote().sendText(message);}@Overridepublicbooleanequals(Objecto){if(this==o){returntrue;}if(o==null||getClass()!=o.getClass()){returnfalse;}WebSocketComponentthat=(WebSocketComponent)o;returnObjects.equals(session,that.session);}@OverridepublicinthashCode(){returnObjects.hash(session);}}@ServerEndpoint注解标识当前WebSocket服务端endpoint地址,本文实际前端访问的ws地址为:ws://localhost:8080/websocket。至此,服务端工作完成。页面VUE端<template><el-cardv-loading="loading"element-loading-spinner="el-icon-loading":body-style="{padding:'5px',backgroundColor:'#eee'}"class="socket-box"shadow="hover"><divclass="socket-box__content":style="{height:(boxHeight-125)+'px'}"id="socket-content"><divv-if="hasMore"@click="loadMore"class="load-more"><span>加载更多</span></div><divv-elsestyle="width:100%;text-align:center;font-size:12px">没有更多了</div><divclass="item"v-for="minmessages":class="checkMe(m)?'sender':''"><divclass="slide"><divclass="avatar":style="{background:m.background}">{{m.name.substring(0,1)}}</div><divclass="meta"><divclass="name">{{m.name}}</div><divclass="date">{{m.createTime|datetime}}</div></div></div><p>{{m.content}}</p></div></div><divclass="socket-box__footer"><el-form@submit.native.prevent><el-form-item><el-inputtype="textarea"resize="none":rows="3":disabled="!connect":placeholder="connect?'输入内容...':'当前连接断开,请刷新重试!'":clearable="true"v-model="message"@keydown.native.enter="submitMsgForm"></el-input></el-form-item><el-form-item><el-button@click="sendMsg(message)":disabled="!connect"style="width:100%"type="primary"size="small">发送(Enter)</el-button></el-form-item></el-form></div></el-card></template><script>import{GET}from"@/api";exportdefault{name:"Chatroom",data(){return{messages:[],message:'',//boxHeight:document.documentElement.clientHeight-85,hasMore:true,pager:{pageNo:1,pageSize:10,total:0},loading:false,connect:false}},props:{boxHeight:{type:Number,required:true}},methods:{submitMsgForm(event){if(event.shiftKey){return;}event.preventDefault();this.sendMsg(this.message)},checkMe(message){letuser=localStorage.getItem("socketUser");if(user){user=JSON.parse(user);returnuser.uid===message.uid}else{returnfalse;}},initWebSocket:function(){this.websock=newWebSocket(`ws://localhost:8080/websocket`);this.websock.onopen=this.websocketonopen;this.websock.onerror=this.websocketonerror;this.websock.onmessage=this.websocketonmessage;this.websock.onclose=this.websocketclose;constthat=this;that.loading=true;GET({url:'/api/personal/web/message/socketData?pageNo=1',callback:res=>{if(res.code===200){that.messages=res.data.messages;that.hasMore=res.data.messages.length===that.pager.pageSize;that.$nextTick(function(){document.getElementById("socket-content").scroll({top:document.getElementById("socket-content").scrollHeight,left:0,behavior:'smooth'})})}that.loading=false}})},sendMsg(data){if(/^\s*$/.test(data)){this.message='';return;}//发送时传入JSON(UID,昵称,内容)constlocal=localStorage.getItem("socketUser");if(local){constl=JSON.parse(local);this.send(l,data)}else{//弹框this.$prompt('首次发表,请输入昵称','提示',{confirmButtonText:'确定',cancelButtonText:'取消',}).then(({value})=>{//随机生成UIDconstuid=this.randomVideoUuid(32,16);constform={uid:uid,name:value,background:`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`};localStorage.setItem("socketUser",JSON.stringify(form));this.send(form,data)}).catch(()=>{this.$message({type:'info',message:'取消输入'});});}},send(obj,data){obj.content=data;obj.createTime=newDate().getTime();this.websock.send(JSON.stringify(obj));this.message='';this.messages.push(obj);this.$nextTick(function(){document.getElementById("socket-content").scroll({top:document.getElementById("socket-content").scrollHeight,left:0,behavior:'smooth'})})},loadMore(){this.loading=true;constthat=this;if(this.hasMore){this.pager.pageNo+=1;GET({url:'/api/personal/web/message/socketData?pageNo='+this.pager.pageNo,callback:res=>{if(res.code===200){that.messages=[...res.data.messages,...that.messages];that.hasMore=res.data.messages.length>=that.pager.pageSize;}that.loading=false;}})}},websocketonopen:function(e){console.log("WebSocket连接成功",e);this.connect=true;},websocketonerror:function(e){console.log("WebSocket连接发生错误");this.connect=false;},websocketonmessage:function(e){constda=JSON.parse(e.data);this.messages.push(da);this.$nextTick(function(){document.getElementById("socket-content").scroll({top:document.getElementById("socket-content").scrollHeight,left:0,behavior:'smooth'})})},websocketclose:function(e){console.log("connectionclosed("+e.code+")");},randomVideoUuid(len,radix){letchars='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');letuuid=[];radix=radix||chars.length;if(len){for(leti=0;i<len;i++)uuid[i]=chars[0|Math.random()*radix];}else{letr;uuid[8]=uuid[13]=uuid[18]=uuid[23]='-';uuid[14]='4';for(leti=0;i<36;i++){if(!uuid[i]){r=0|Math.random()*16;uuid[i]=chars[(i===19)?(r&0x3)|0x8:r];}}}returnuuid.join('');},},mounted(){this.initWebSocket();}}</script>本段代码为简单的Vue实现的网页聊天室代码,其中@/api为自己简单封装的JS函数,用户初次进入页面时会生成一个随机UID保存到localStorage中,在mounted周期中初始化websocket连接。本聊天室最终效果地址:https://web.coralcloud.cn/blog/message
1.@RestController注解相当于@ResponseBody+@Controller合在一起的作用。2.如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return里的内容。3.如果需要返回到指定页面,则需要用@Controller配合视图解析器InternalResourceViewResolver才行。4.如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。)
Centos安装ApacheHadoop2.7.7准备文件:hadoop-2.7.7.tar.gz一、安装JDK安装Hadoop之前需要保证JDK8成功安装java-version二、上传Hadoop压缩包上传成功后解压文件:tar-zxvfhadoop-2.7.7.tar.gz假设解压后的Hadoop目录为:/home/hadoop/hadoop-2.7.7注意配置HADOOP_HOME环境变量exportHADOOP_HOME=/home/hadoop/hadoop-2.7.7exportPATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin三、配置服务器免密登录$ssh-keygen-trsa-P''-f~/.ssh/id_rsa$cat~/.ssh/id_rsa.pub>>~/.ssh/authorized_keys$chmod0600~/.ssh/authorized_keys执行完成后:sshmaster命令则能够跳过输入密码阶段直接连接四、修改配置==配置文件所在位置:$HADOOP_HOME/etc/hadoop==core-size.xml<configuration><property><name>fs.defaultFS</name><value>hdfs://master:9000</value></property></configuration>hdfs-size.xml<configuration><property><name>dfs.replication</name><value>1</value></property></configuration>mapred-site.xml<configuration><property><name>mapreduce.framework.name</name><value>yarn</value></property><property><name>mapreduce.application.classpath</name><value>$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/*:$HADOOP_MAPRED_HOME/share/hadoop/mapreduce/lib/*</value></property></configuration>yarn-site.xml<configuration><property><name>yarn.nodemanager.aux-services</name><value>mapreduce_shuffle</value></property><property><name>yarn.nodemanager.env-whitelist</name><value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value></property></configuration>五、启动初始化HDFShdfsnamenode-format启动HDFSstart-dfs.sh启动YARNstart-yarn.sh启动成功后访问http://master:50070查看HDFS状态六、相关命令start-dfs.sh启动HDFS(namenode/datanode/SecondaryNamenode)stop-dfs.sh停止HDFSstart-yarn.sh启动Yarnstop-yarn.sh停止Yarnstart-all.sh启动HDFS和Yarnstop-all.sh停止HDFS和Yarn
- SpringBoot+Thymleaf项目初入(五) - 图片验证码
- SpringBoot+Thymleaf项目初入(四) - 用户登录页面优化
- SpringBoot+Thymleaf项目初入(三) - 用户登录
- SpringBoot+Thymleaf项目初入(二) - 配置基础页面访问
- SpringBoot+Thymleaf项目初入(一) - 基础项目搭建
- MyBatis之where关键字与<where>标签的区别
- 文件上传之@RequestParam与@RequestPart
- Spring注解之@Component
- SpringBoot框架之@Controller和@RestController的区别?
- Centos安装ApacheHadoop2.7.7
