- ?
我的java后端工作1年经验和技术总结
郦不尤
展开
1.引言
毕业已经一年有余,这一年里特别感谢技术管理人员的器重,以及同事的帮忙,学到了不少东西。这一年里走过一些弯路,也碰到一些难题,也受到过做为一名开发却经常为系统维护和发布当救火队员的苦恼。遂决定梳理一下自己所学的东西,为大家分享一下。
经过一年意识到以前也有很多认识误区,比如:
偏爱收集,经常收集各种资料视频塞满一个个硬盘,然后心满意足的看着容量不行动。
不重基础,总觉得很多基础东西不需要再看了,其实不懂的地方很多,计算机程序方面任何一个结果都必有原因,不要只会用不知道原理,那是加工厂出来的。现在ide查看代码那么方便,ctrl+点击就进入了JDK查看实现细节。
好高骛远,在计算机基础不牢固的情况下,总想着要做架构,弄分布式,搞大数据之类。
不重视性能,只求能实现功能,sql查询是不是可以优化,是否有算法妙用,大对象是否要清除。
不重视扩展性,模块之间紧密耦合,常用方法不提取成工具类,调用关系混乱等问题。
……
本文重点不在这些,故只列举了一小部分,下面进入正题。
2.语法基础
2.1 Java类初始化顺序
这是所有情况的类初始化顺序,如果实际类中没有定义则跳过:父类静态变量——父类静态代码块——子类静态代码块——父类非静态变量——父类非静态代码块——父类构造函数——子类非静态变量——子类非静态代码块——子类构造函数
2.2 值传递和引用传递
可能很多人对此不屑一顾,心想老子都工作一年了,对这些还不熟悉吗?但实际情况并非这样,JDK中东西全部熟悉了吗?以一个最简单的例子开始,你觉得下图中代码执行完之后fatherList中的元素是什么?
这是一个最基础的值传递和引用传递的例子,你觉得好简单,已经想跃跃欲试的挑战了,那么请看下面的,StringBuffer很好理解,但是当你执行一遍之后发现是不是和预想中的输出不一样呢?String不是引用类型吗,怎么会这样呢?如果你无法理解,那么请看下String的实现源码,了解下其在内存中分配的实现原理。
如果你想学习Java可以来这个群,首先是二二零,中间是一四二,最后是九零六,里面可以学习和交流,也有大量的学习资料可以下载。
2.3 集合的使用
这部分几乎每个人都会用到,而且大家还都不陌生。下图来源于互联网,供大家复习一下。但是利用集合的特性进行巧妙的组合运用能解决优化很多复杂问题。Set不可重复性,List的顺序性,Map的键值对,SortSet/SortMap的有序性,我在工作中有很多复杂的业务都巧妙的使用了这些,涉及到公司保密信息,我就不贴出代码了。工作越久越发现这些和越巧妙。
2.3 异常处理
1.看着try、catch、finally非常容易,如果和事务传播结合在一起,就会变得极其复杂。
2.finally不一定必须执行,return在catch/finally中处理情况(建议亲自操刀试一下)。
3.catch中可以继续抛自定义异常(并把异常一步步传递到控制层,利用切面抓取封装异常,返回给调用者)。
2.4 面向对象思想
一提起面向对象,大家都知道抽象、封装、继承、和多态。但是实际工作经验中又知道多少呢,对于项目中如何巧用估计更不要提了。
共性的机会每个都需要用的建立基类,如每个控制层方法可能要通过security获取一个登录用户id,用于根据不同的用户操作不同的数据,可以抽象出一个应用层基类,实现获取id的protect方法。同理DAO层可以利用泛型提取出一个包含增删改查的基类。
多态的Override:基类的引用变量不仅可以指向基类的实例对象,也可以指向其子类的实例对象,如果指向子类的实例对象,其调用的方法应该是正在运行的那个对象的方法。在策略模式中使用很普遍。
提到面向对象,就不可避免的要说设计模式,在工作中,一个技术大牛写的一个类似策略模式(更复杂一点),十分巧妙的解决了各种业务同一个方法,并且实现了订单、工单、业务的解耦,看得我是非常佩服。我想很多面试中都会问道单例模式吧,还没有理解的建议去看一看。
3.多线程
3.1 线程安全
这个是老生常谈的问题了,但是确实是问题和bug高发区。线程同步问题不需要单独写了,想必大家都清楚,不太熟悉的建议百度一下。
3.1.1 线程安全问题
1.代码中如果有同步操作,共享变量要特别注意(这个一般都能意识到)
2多个操作能修改数据表中同一条数据的。(这个容易被忽略,业务A可能操作表a,业务B也可以操作表a,业务A、B即使在不同的模块和方法中,也会引起线程安全问题。例如如果一个人访问业务A接口,另一个人访问业务B接口,在web中每个业务请求都是会有单独的一个线程进行处理的,就会出现线程安全问题)。
3.不安全的类型使用,例如StringBuffer、StringBuild,HashTable、HashMap等。在工作中我就遇到过有人在for循环进行list的remove,虽然编译器不报错,程序可以运行,但是结果却可想而知。
4.Spring的bean默认是单例的,如果有类变量就要特别小心了(一般情况下是没人在控制层、业务层、DAO层等用类变量的,用的话建议是final类型,例如日志log,gson等)。
5.多个系统共享数据库情况,这个其实和分布式系统类似
用户重复提交问题(即使代码中从数据库读取是否存在进行限制不能解决问题)
3.1.2 线程安全解决
在需要同步的地方采用安全的类型。
JDK锁机制,lock、tryLock,synchronized,wait、notify、notifyAll等
Concurrent并发工具包,在处理一些问题上,谁用谁知道。强烈建议查看源码!
数据表加锁。(除非某个表的访问频率极低,否则不建议使用)
涉及分布式的,采用中间件技术例如zookeeper等解决。
3.2 异步
异步使用场景不影响主线程,且响应较慢的业务。例如IO操作,第三方服务(短信验证码、app推送、云存储上传等)。
如果异步任务很多,就需要使用任务队列了,任务队列可以在代码级别实现,也可以利用redis(优势太明显了)。
3.3 多线程通信
这方面文章非常多,这里不在详述。
1.共享变量方式(共享文件、全局变量,信号量机制等)
2.消息队列方式
3. 忙等,锁机制
3.4多线程实现
1.集成Thread类,重写(这里的重写指的是override)run方法,调用start方法执行。
2.实现Runable接口,实现run方法,以Runable实例创建thread对象。
3.实现Callable接口,实现call方法,FutureTask包装callable接口,FutureTask对象创建thread对象,常用语异步操作,建议使用匿名内部类,方便阅读和使用。
额外需要说明的是:
1.理解thread的join方法;
2.不要认为volitate是线程安全的(不明白原因的建议去看jvm运行时刻内存分配策略);
3.sleep时间片结束后并不保证立马获取cpu。
4.ThreadLocal能够为每一个线程维护变量副本,常用于在多线程中用空间换时间。
4. 开源框架
4.1 Hibernate、Mybatis
相信每一个java程序员对这些都不陌生,这里不再详述。
需要说明的主要以下几点:
1.hibernate一级缓存(内置session缓存),二级缓存(可装配sessionFactory缓存),二级缓存会引起并发问题。
2.hibernate延迟加载原理理解。
3.hibernate 的get、load方法,sava、persist、savaOrUpdate方法区别
4.session重建了关联关系却并没有同数据库进行同步和更新
5.hibernate session关联关系:detached对象、persistent对象
6.Spring data集成,注解方式配置属性和实体。
7.mybatis 插件。
8.分页查询(数据库)。
9.连接池技术
4.2 Spring IOC
4.1.1 Spring bean
1.bean注入 注解方式方便易读,引用第三方(数据库连接,数据库连接池,JedisPool等)采用配置文件方式。
2. bean作用域:Singleton,prototype,request,session,global session
3.bean生命周期:如下图所示(图片来源于互联网):
4.3 Spring AOP
基本概念:关注点、切面Aspect、切入点pointcut、连接点joinpoint、通知advice、织入weave、引入introduction。
Spring AOP支持5中类型通知,分别是MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice、MethodInterceptor、IntroductionInterceptor(吐槽一下名字太长)
实现方式如下:
1.基于代理的AOP
2.基于@Aspect注解驱动的切面。(强烈推荐:可读性好,易维护,易扩展,开发快)
3.纯POJO切面。
4.注入式Aspect切面。
4.4 Srping事务
4.4.1 事务传播
概念:某些操作需要保证原子性,如果中间出错,需要事务回滚。如果某个事务回滚,那么调用该事务的方法中的事务的作出如何的动作,就是事务传播。
短时间内写不清楚
事务传播属性:
1. PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2. PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
3. PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
4. PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
5. PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6. PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
事务隔离级别:
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
4.5 其他Spring 技术栈
spring boot 轻量级启动框架
spring security 用户权限管理,根据角色和用户,实现UserDetailsService,进行自定义权限管理。
spring task 代码级定时任务,注解方式,使用起来非常方便。需要注意的是,如果某次定时任务出了异常而没有进行处理,会导致接下来定时任务失效。如果各个任务相互独立,可以简单用try,catch包围(之前就吃过这方面的亏)。
spring data 注解方式定义实体,属性等
spring mvc 简单明了的mvc框架。url传值、数组传值、对象传值、对象数组等传值类型,上传/下载文件类型需要注意。
spring restful 注意命名,对命名要求很严格。
spring shell 命令行方式执行命令,救火、导入导出数据等用起来非常方便、制作报表。
5. Web基础
5.1 web容器启动
1.web.xml加载顺序: listener -> filter ->servlet
2.webt容器启动过程,java新手很怕配置文件,理解完这些有助于熟悉配置文件 http://blog.csdn/u014431852/article/details/47042895
5.2 Servlet、Interceptor、Listener、Filter
Servlet 接收请求返回响应,最原始的web业务处理类。
Interceptor 拦截器,可以实现HandlerInterceptor接口自定义拦截器,在日志记录、权限检查、性能监控、通用行为等场景使用,本质是AOP。
Listener 监听器 常用于统计在线人数等纵向功能。
Filter 过滤器 在请求接口处理业务之前改变requset,在业务处理之后响应用户之前改变response。如果某些数据不加密,很容易用抓包工具加filter作弊。
5.3 web项目结构
5.3.1 mvn结构
熟练掌握几种常见的mvn项目结构,mvn可以自动生成,这里不再详述。
5.3.2 mvn包管理
1.版本号尽量几种在一个文件中便于管理。
2.spring milestone包解决spring包冲突问题。
3.mvn dependency:tree命令分析所有包依赖,对于冲突的在pom文件中
包围起来 5.3.3 版本控制
1.git、svn等
2.代码冲突解决方案
3.分支管理。
对于某个稳定版本上线后,如果在此基础上开发新功能,一定要新建分支,在新分支上提交代码,最后在新版发布时合并分支。修改运营环境bug切换到主分支进行修改
5.4 Http请求
5.4.1 请求方法
post、get、put、head、delete、copy、move、connect、link、patch,最常用的是前4、5个。
5.4.2 请求头,状态码
常用的请求头有Accept(下载文件会特殊使用)、Accept-Charset(设置utf-8字符集)、Content-Type(json等配置)等
常用的响应头有Content-Type、Content-Type、Content-Length等,偏前端,不再详述。
6. 系统架构
接触的不是特别多,目前用到的只是服务器主从备份。Nginx反向代理进行配置。
多个项目nginx配置
Spring Mvc 用json数据进行交互,配置json转换的servlet。
封装返回值
自定义RunEnvironmentException(状态码,原因),覆盖原有Exception,切面ExceptionHandler抓取Exception并封装到返回值中(前后端松耦合)
<... - ?
“程序员大佬”用 Java 实现的博客系统,来一起创建个自己博客吧!
惜文
展开
简介
Solo 是一款一个命令就能搭建好的 Java 开源博客系统,并内置了 15+ 套精心制作的皮肤。除此之外,Solo 还有着非常活跃的社区,文章分享到社区后可以让很多人看到,产生丰富的交流互动。
Solo 的第一个版本发布于 2010 年,至今已经非常成熟稳定,请放心使用
功能
Solo 沉淀至今的每一个功能你应该都会用到。我们不会将只有“20%”用户使用的功能添加进来,只有这样才能保持博客系统本该有的纯净,足够轻量才能带来简约的使用体验。
Markdown / Emoji
聚合分类 / 标签
自定义导航(页面、链接)
草稿夹
评论/回复邮件提醒
随机文章 / 相关文章 / 置顶 / 更新提醒
自定义文章永久链接
自定义站点 SEO 参数
自定义公告 / 页脚
多个签名档
代码高亮
多皮肤,多端适配 / 社区皮肤
多语言 / 国际化
上传七牛云
友情链接管理
多用户写作,团队博客
SQL 文件导出
Hexo/Jekyll 导入
插件系统
Atom / RSS 订阅
Sitemap
MetaWeblog API
CDN 静态资源分离
如果有新版可用,升级过程也是非常简单的,只需要重新部署新版本就可以,不用运行额外的任何脚本。
然后就让我们来看看怎么
安装、配置、备份以及常见问题吧!
获取项目源码,项目讲解,知识点分享,学习交流,那就加入小编的Java学习交流群吧!
616 959 444
安装
安装前先准备好 Java 环境,请使用
JDK8 或以上
版本。Solo 提供了两种部署模式,分别是独立模式和容器模式。数据库默认是使用内嵌的 H2 数据库,也支持 MySQL,稍后会详细介绍。
对于系统内存要求,最低 512M,推荐 1G。
独立模式,JDK 环境准备好之后下载最新的 Solo 包解压,进入解压目录执行!
独立模式使用内嵌的 Jetty 容器进行部署,解压 war 包后仅需要一个命令就能启动:
Windows:
java -cp WEB-INF/lib/*;WEB-INF/classes org.b3log.solo.Starter
Unix-like:
java -cp WEB-INF/lib/*:WEB-INF/classes org.b3log.solo.Starter
注意
:上面的命令都是前台运行的,退出 shell 后会被终止。比如 Linux 上不中断运行需要使用 nohup。
容器模式
使用 Jetty 或者 Tomcat(
版本要求至少 9
)进行部署,将 war 包放到容器的 webapps 目录下即可。
独立 vs 容器
两种模式各有千秋:
独立模式:一个命令就能启动,如果你对 Java Web 不太熟悉,建议使用该方式
容器模式:可以和已有的程序一起部署在同一个容器中,这样可以节省内存
细节配置
主要的配置文件有两个,它们都存放在 WEB-INF/classes 目录下。
latke.properties:用于配置域名和端口,请配置为浏览器访问时候的域名和端口
local.properties:用于配置数据库,要切换为 MySQL 的话请在这里配置
皮肤
下载的 war 包中自带了所有官方皮肤,如果你是自己拉源码构建的,可以到这里下载皮肤。
皮肤放到 skins 目录下后重启服务,在工具 -> 偏好设定 ->皮肤中选择使用即可。
NGINX 示例
相应的 latke.props 配置:
初始化后
初始化成功后
强烈建议
到管理后台 -> 工具 ->偏好设定中进行一下配置。
信息配置
博客基本信息:标题、子标题、SEO 信息
HTML head:可以配置脚本,比如百度统计
公告:可以使用 HTML 和脚本进行配置
页脚:主要用来放备案信息,也可以使用 HTML 和脚本进行配置
签名档
最多可以配置 3 个签名档,发布文章的时候选择一个使用,可以使用 HTML 和脚本进行配置。
参数设置
下面是一些比较有特色或重要的参数:
编辑器类型
列表显示方式:仅标题 / 标题 + 摘要 / 标题 + 正文
各种分页参数
文章更新提示:启用后一旦某篇文章更新过,则会在文章标题处显示“有更新”的提示,并且排序靠前
允许注册:开放注册后其他人可以注册成为“访客用户”,方便评论时不用每次都填写基本信息。管理员可以在用户管理中看到当前的所有用户,并可以改变用户角色
导入数据
如果你之前使用的系统支持这个特性,可以先用客户端工具导出文章到本地,然后再导入 Solo,
可参考下面的 MetaWeblog API 配置。
静态博客 /Markdown
https://hacpai/article/1498490209748
备份
war 包
如果你修改过代码请记得备份整体的 war 包,如果没有修改过则只用备份下面的配置文件。
配置文件
进行版本升级时需要,建议备份 WEB-INF/classes/ 目录下的三个文件
:
latke.properties
local.properties
mail.properties(如果修改过的话)
数据库
H2:备份用户 home 目录下的 solo_h2 文件夹
MySQL:使用 MySQL 相关备份工具,或者到博客后台工具 -> 其他中进行 SQL 导出
强烈建议定时备份数据!!!
升级
使用在跑着的老版本的配置文件覆盖新版本 war 中的(或者重新再配置一次),然后直接部署就好,启动时会自动进行升级。要确认升级是否成功的话留意一下日志,或者查看 option 表中的 version 行。
:不能进行跨版本升级,建议紧跟我们的发布步伐
下面是两位用户升级 Solo 的经验分享,请参考一下:
https://hacpai/article/1487432682174
https://hacpai/article/1488440206134
其他一些特性
多用户
可以几个用户同时使用一个博客发布文章,主要用在团队博客这个场景。权限方面做了简单隔离,非管理员用户可以看到其他用户的博文 / 评论列表,但是不能进行操作。
RSS/Atom
提供两种订阅供稿:Atom 1.0、RSS 2.0,分别可以对博客文章列表、标签 - 文章列表进行供稿:
博客文章列表
Atom: /blog-articles-feed.do
RSS: /blog-articles-rss.do
标签 - 文章列表
Atom: /tag-articles-feed.do?oId=${tagId}
RSS: /tag-articles-rss.do?oId=${tagId}
浏览器直接打开可能会出现编码问题,可使用阅读器查看。
自动生成全站文章的 sitemap.xml,有利于 SEO。
前台皮肤切换
通过 URL 带参(比如 http://demo.b3log.org/?skin=finding)来确定渲染使用的皮肤。
使用场景举例:
在不安装 Solo 的情况下可以方便预览各个皮肤(在 Demo 上)
方便二次开发时集成切换皮肤
博主可以让访客体验到不同的效果,比如:这个皮肤好看?还是这个好看?
1,只有在首页(/)会取参数skin=xxx
2,如果带有就记录到 Cookie 里面,如果带有skin=default或皮肤不存在则清空 Cookie
3,如果要切换成后台默认的皮肤,在首页带参skin=default
站外相关文章
“站外相关文章”指的是其他人使用 Solo 发布的文章,该文章含有与你的文章相同的标签。该功能主要是为了加强各个 Solo 博客之间的互动性,让博客访问者可以更有效地访问到相关的内容。
这是 B3log 构思 的一部分实现,欢迎各位大家积极参与进来
https://hacpai/b3log
MetaWeblog API 是用于离线管理文章的(比如使用 WLW),目前支持以下 APIs:
blogger.getUsersBlogs – 获取博客
metaWeblog.getCategories – 获取标签列表
metaWeblog.getRecentPosts – 获取最新文章列表
metaWeblog.getPost – 获取文章
metaWeblog.newPost – 发布文章 / 保存草稿
metaWeblog.editPost – 编辑文章
blogger.deletePost – 删除文章
配置地址:/apis/metaweblog,用户名 / 密码:管理员的口令
FAQ
初始化卡住
如果初始化向导页面已经正常显示,但是填完表单后点击“初始化”按钮后卡住,说明可能是 serverPort没有配置正确,这个端口需要配置为浏览器访问时候的端口,而不是容器启动的监听端口。
如何引入自定义静态资源,比如 .mp3?
请参考 WEB-INF/static-resources.xml 中的配置,加入自定义资源的路径匹配后重启。
如何获得更好的 Markdown 渲染效果?
Solo 默认是使用内嵌的 flexmark 进行 md 渲染,这个项目还比较新,对有的场景下的 md 渲染效果处理不是很好。如果你想要获得更好的 md 渲染效果需要这样做:
安装 Node.js
2.安装 marked:npm install marked --save
3.在 Solo 目录下执行
node js/marked/http.js以启动 markdown 解析引擎(你可能需要 nohup),需要 8250端口可用
4.重启 Solo 后就会使用 marked 作为 markdown 渲染引擎了
谢谢大家的观看,很晚了。今天先写到这里吧!后面会一步步的全部写出来,如果有什么不对或不同看法的请留言!谢谢!
后续:
开发环境、项目结构、框架说明
开发步骤、模版变量
插件机制、处理流程
- ?
Java输出流FileOutputStream使用详解
方半烟
展开
前面介绍了如何应用输入流FileInputStream从本地文件读取数据。本节介绍应用输出流FileOutputStream把数据写入本地文件。
用FileOutputStream写入文件流程如下:
使用FileOutputStream写入文件的过程同使用FileInputStream过程相同,都是先用File类打开本地文件,实例化输入输出流,然后调用流的读写方法读取或写入数据,最后关闭流。
FileOutputStream的构造方法
FileOutputStream提供了4个常用构造方法,用于实例化FileOutputStream对象,不同的场景使用不同的构造方法。
场景1:使用File对象打开本地文件,从文件读取数据。
场景2:不使用File对象,直接传入文件路径。
FileOutputStream的构造方法允许直接传入文件路径,而无须使用File对象。查看该构造方法的源代码,其内部使用了File对象打开文件。
场景3:打开文件,在文件的尾部追加写入数据。
场景要求在文件的尾部写入数据,由于前面两个构造函数都是文件开始写入数据(覆盖原文件),因此不能使用前面2个场景的构造函数。FileOutputStream提供了另外两个构构造方法,分别是:
FileOutputStream(File file, boolean append);
FileOutputStream(String name, boolean append);
同前面的构造方法相比,这两个构造方法各多了一个boolean参数append。append参数为true时,数据从文件尾部写入;append参数为false时,数据覆盖原文件。
FileOutputStream的写入方法
FileOutputStream类提供了多种文件写入方法,可以单独写一个字节到文件,也可以写一个byte数组到文件,也可以取byte数组的部分数据写入到文件。
例1:使用write(int b)方法写入文件。
例子程序首先调用File类的createNewFile()创建new.txt文件,然后将str内容写入到新创建的new.txt文件中。
例2:使用write(byte[] b)方法写入文件。
write(byte[] b)方法用于将b.length个字节从指定的byte数组写入到输出流。
String类的getBytes()方法可以将字符串转换为byte数组,使用FileOutputStream 类的write(byte[] b)方法,将转换的byte数组写入文件。
例3:使用write(byte[] b,int off,int len)方法写入文件。
该方法将len个字节的数据,并从数组b的off位置开始写入到输出流。
程序把指定的str内容写入到文件,fos.write(str.getBytes(),5,10)语句的第一个参数为byte数组,第二个参数5是从byte数组的下标5开始,第三个参数是写入的字节数。程序执行后,写入的内容为“is new file”。
使用该方法一定要注意数组越界的问题。例如,byte数组长度为20,从第下标12开始,写入15个字节到文件,就会造成数组越界,程序报错。
例4:使用FileOutputStream复制文件
复制文件是将源文件数据写入到新文件,在实际编程中,实现文件的复制有很多种方法,本案例使用FileInputStream和FileOutputStream实现文件的复制。
代码中的copyFile完成文件的复制,在复制之前,先判断一下源文件是否存在,然后申请一个byte数组,用于存储读取的源文件数据,该数组大小与源文件总字节数相同,读取成功后,再将数组内容写入到目标文件。程序输出结果如下图所示:
■ 知识点拨
使用FileOutputStream流可以写入字节数据到目标文件,FileOutputStream提供了单字节写入和byte数组写入两种方式。建议使用byte数组写入,将待写入的数据存储到一个byte数组中,然后再写入文件。当写入的文件已经存在时,需要指明写入方式是覆盖还是追加。
- ?
如何导出Java应用程序的内存快照文件
弗朗西斯
展开
导出Java应用程序的内存快照是分析Java程序是否存在泄露和解决泄露的第一步。下面小编将介绍下如何在windows和linux平台下,导出Java应用的内存快照文件。
在windows下找到要导出的Java应用的进程号。比如我要导出本机的Eclipse的内存快照,因为Eclipse也是Java应用。首先要找到Eclispe的进程号。在命令行输入:tasklist | findstr eclipse。
可以看到,Eclispe的进程号是8052。然后在命令行输入:jmap -dump:format=b,file=elipse.hprof 8052。file=elipse.hprof意思是设置生成的文件名,8052就是Java程序的进程号。
如果是在Linux系统下面,在命令行输入:ps -ef | grep eclipse。
可以看到eclipse的进程号是2622。同样,在命令行输入:jmap -dump:format=b,file=elipse.hprof 2622。
把生成的elipse.hprof在SecureCRT命令行输入:sz elipse.hprof,把文件下载到本地,用MAT之类的工具进行分析就可以了。
怎么样,是不是很简单,如果觉得有用,请点击投票,小编会继续努力谢谢你的支持哦。
- ?
处理Java大数据有什么技巧
暖阳
展开
Java在处理数据量比较大的时候,加载到内存必然会导致内存溢出,而在一些数据处理中我们不得不去处理海量数据,那Java是如何处理大数据的呢?有什么技巧吗?在做数据处理中,我们常见的手段是分解,压缩,并行,临时文件等方法。
例如,我们要将数据库(不论是什么数据库)的数据导出到一个文件,一般是Excel或文本格式的CSV;对于Excel来讲,对于POI和JXL的接口,你很多时候没有办法去控制内存什么时候向磁盘写入,很恶心,而且这些API在内存构造的对象大小将比数据原有的大小要大很多倍数,所以你不得不去拆分Excel,还好,POI开始意识到这个问题,在3.8.4的版本后,开始提供cache的行数,提供了SXSSFWorkbook的接口,可以设置在内存中的行数,不过可惜的是,他当你超过这个行数,每添加一行,它就将相对行数前面的一行写入磁盘(如你设置2000行的话,当你写第20001行的时候,他会将第一行写入磁盘),其实这个时候他的临时文件,以至于不消耗内存,不过这样你会发现,刷磁盘的频率会非常高,我们的确不想这样,因为我们想让他达到一个范围一次性将数据刷入磁盘,比如一次刷1M之类的做法,可惜现在还没有这种API,很痛苦,我自己做过测试,通过写小的Excel比使用目前提供刷磁盘的API来写大文件,效率要高一些,而且这样如果访问的人稍微多一些磁盘IO可能会扛不住,因为IO资源是非常有限的,所以还是拆文件才是上策;而当我们写CSV,也就是文本类型的文件,我们很多时候是可以自己控制的,不过你不要用CSV自己提供的API,也是不太可控的,CSV本身就是文本文件,你按照文本格式写入即可被CSV识别出来;如何写入呢?下面来说说。。。
在处理数据层面,如从数据库中读取数据,生成本地文件,写代码为了方便,我们未必要1M怎么来处理,这个交给底层的驱动程序去拆分,对于我们的程序来讲我们认为它是连续写即可;我们比如想将一个1000W数据的数据库表,导出到文件;此时,你要么进行分页,Oracle当然用三层包装即可,MySQL用limit,不过分页每次都会新的查询,而且随着翻页,会越来越慢,其实我们想拿到一个句柄,然后向下游动,编译一部分数据(如10000行)将写文件一次(写文件细节不多说了,这个是最基本的),需要注意的时候每次buffer的数据,在用outputstream写入的时候,最好flush一下,将缓冲区清空下。
来设置游标的方式,以至于游标不是将数据直接cache到本地内存,然后通过设置statement.setFetchSize(200);设置游标每次遍历的大小;OK,这个其实我用过,oracle用了和没用没区别,因为oracle的jdbc API默认就是不会将数据cache到java的内存中的,而mysql里头设置根本无效,我上面说了一堆废话,呵呵,我只是想说,java提供的标准API也未必有效,很多时候要看厂商的实现机制,还有这个设置是很多网上说有效的,但是这纯属抄袭;对于oracle上面说了不用关心,他本身就不是cache到内存,所以java内存不会导致什么问题,如果是mysql,首先必须使用5以上的版本,然后在连接参数上加上useCursorFetch=true这个参数,至于游标大小可以通过连接参数上加上:defaultFetchSize=1000来设置,
上次被这个问题纠结了很久(mysql的数据老导致程序内存膨胀,并行2个直接系统就宕了),还去看了很多源码才发现奇迹竟然在这里,最后经过mysql文档的确认,然后进行测试,并行多个,而且数据量都是500W以上的,都不会导致内存膨胀,GC一切正常,这个问题终于完结了。
Java在处理大数据的时候还是有一些小技巧的,正确运用这些小技巧,有时候在处理问题时往往会事半功倍。
- ?
一行代码完成Java的Excel读写
斯特拉尔松
展开
前段时间在 github 上发现了阿里的 EasyExcel 项目,觉得挺不错的,就写了一个简单的方法封装,做到只用一个函数就完成 Excel 的导入或者导。刚好前段时间更新修复了一些 BUG,就把我的这个封装分享出来,请多多指教。
附上源码:
https://github/HowieYuan/easyexcel-method-encapsulation
EasyExcel
EasyExcel 的 github 地址:
https://github/alibaba/easyexcel
EasyExcel 的官方介绍:
可以看到 EasyExcel 最大的特点就是使用内存少,当然现在它的功能还比较简单,能够面对的复杂场景比较少,不过基本的读写完全可以满足。
一. 依赖
首先是添加该项目的依赖,目前的版本是 1.0.2。
com.alibaba easyexcel 1.0.2 二. 需要的类
1. ExcelUtil
工具类,可以直接调用该工具类的方法完成 Excel 的读或者写。
2. ExcelListener
监听类,可以根据需要与自己的情况,自定义处理获取到的数据,我这里只是简单地把数据添加到一个 List 里面。
publicclassExcelListenerextendsAnalysisEventListener {//自定义用于暂时存储data。//可以通过实例获取该值private List
3. ExcelWriterFactroy
用于导出多个 sheet 的 Excel,通过多次调用 write 方法写入多个 sheet。
4. ExcelException
捕获相关 Exception。
三. 读取 Excel
读取 Excel 时只需要调用 ExcelUtil.readExcel() 方法:
@RequestMapping(value = "readExcel", method = RequestMethod.POST)public Object readExcel(MultipartFile excel) {return ExcelUtil.readExcel(excel, new ImportInfo());}
其中 excel 是 MultipartFile 类型的文件对象,而 new ImportInfo() 是该 Excel 所映射的实体对象,需要继承 BaseRowModel 类,如:
publicclass ImportInfo extends BaseRowModel {@ExcelProperty(index = 0)privateString name;@ExcelProperty(index = 1)privateString age;@ExcelProperty(index = 2)privateString email;publicString getName() {return name; }publicvoid setName(String name) {this.name = name; }publicString getAge() {return age; }publicvoid setAge(String age) {this.age = age; }publicString getEmail() {return email; }publicvoid setEmail(String email) {this.email = email; }}
作为映射实体类,通过 @ExcelProperty 注解与 index 变量可以标注成员变量所映射的列,同时不可缺少 setter 方法。
四. 导出 Excel
1. 导出的 Excel 只拥有一个 sheet
只需要调用 ExcelUtil.writeExcelWithSheets() 方法:
@RequestMapping(value = "writeExcel", method = RequestMethod.GET)publicvoidwriteExcel(HttpServletResponse response) throws IOException { List
list = getList(); String fileName = "一个 Excel 文件"; String sheetName = "第一个 sheet"; ExcelUtil.writeExcel(response, list, fileName, sheetName, new ExportInfo()); } fileName,sheetName 分别是导出文件的文件名和 sheet 名,new ExportInfo() 为导出数据的映射实体对象,list 为导出数据。
对于映射实体类,可以根据需要通过 @ExcelProperty 注解自定义表头,当然同样需要继承 BaseRowModel 类,如:
publicclass ExportInfo extends BaseRowModel {@ExcelProperty(value = "姓名" ,index = 0)privateString name;@ExcelProperty(value = "年龄",index = 1)privateString age;@ExcelProperty(value = "邮箱",index = 2)privateString email;@ExcelProperty(value = "地址",index = 3)privateString address;}
value 为列名,index 为列的序号。
如果需要复杂一点,可以实现如下图的效果:
对应的实体类写法如下:
publicclass MultiLineHeadExcelModel extends BaseRowModel {@ExcelProperty(value = {"表头1","表头1","表头31"},index = 0)privateString p1;@ExcelProperty(value = {"表头1","表头1","表头32"},index = 1)privateString p2;@ExcelProperty(value = {"表头3","表头3","表头3"},index = 2)private int p3;@ExcelProperty(value = {"表头4","表头4","表头4"},index = 3)private long p4;@ExcelProperty(value = {"表头5","表头51","表头52"},index = 4)privateString p5;@ExcelProperty(value = {"表头6","表头61","表头611"},index = 5)privateString p6;@ExcelProperty(value = {"表头6","表头61","表头612"},index = 6)privateString p7;@ExcelProperty(value = {"表头6","表头62","表头621"},index = 7)privateString p8;@ExcelProperty(value = {"表头6","表头62","表头622"},index = 8)privateString p9;}
2. 导出的 Excel 拥有多个 sheet
调用 ExcelUtil.writeExcelWithSheets() 处理第一个 sheet,之后调用 write() 方法依次处理之后的 sheet,最后使用 finish() 方法结束。
publicvoidwriteExcelWithSheets(HttpServletResponse response) throws IOException { List
list = getList(); String fileName = "一个 Excel 文件"; String sheetName1 = "第一个 sheet"; String sheetName2 = "第二个 sheet"; String sheetName3 = "第三个 sheet"; ExcelUtil.writeExcelWithSheets(response, list, fileName, sheetName1, new ExportInfo()) .write(list, sheetName2, new ExportInfo()) .write(list, sheetName3, new ExportInfo()) .finish();} write 方法的参数为当前 sheet 的 list 数据,当前 sheet 名以及对应的映射类。
扩展阅读
代码整洁之道|最佳实践小结
Javascript 将 HTML 页面生成 PDF 并下载
Java POI 导出EXCEL经典实现 Java导出Excel弹出下载框
来源:https://juejin.im/post/5ba320546fb9a05d0b14304b
文章来源网络,版权归作者本人所有,如侵犯到原作者权益,请与我们联系删除
- ?
认识Java类库,实现基本的输出与输入
好心人
展开
课程导言
【在上节课了解了变量的作用及如何声明变量,本节课探讨Java类库以及基本的输出与输入。通过本课的学校,你将掌握如何输出内容到控制台,如何从获得用户从键盘输入的数据,并了解类库的使用方法】
在程序运行过程中,既需要输入数据,也需要输出数据。例如,求长方形面积算法要求用户输入长方形的长度和宽度值,求出面积后,将结果输出到控制台。在Java程序中,控制台是指运行Java程序的窗口。例如,在Windows命令行窗口下运行程序时,控制台是Windows命令行窗口,在集成开发工具Eclipse运行Java程序时,控制台是Eclipse提供的程序运行窗口,也称为Java console。
课程分为三个小节,第一小节介绍Java类库,Java类库为开发者提供一组程序集合,开发者可以直接使用Java类库提供的程序集合完成诸如输入输出等功能;第二小节介绍Java类库中的Sysytem类,Sysytem类提供了系统控制以及输出信息到控制台的方法;第三小节介绍Java类库中的Scanner类,Scanner类提供了从键盘等外部设备输入数据的功能。
第一小节 Java类库
类库是一组类的集合,一个类可以帮助开发者完成一些通用功能,提高开发速度和质量,这些类可以被开发者直接使用。
Java类库以包层次的方式对外提供,可以把Java包理解为文件目录层次,最外层的目录为Java,Java包含lang、util等子目录,util子目录又包含Scanner、Properties等类文件,也包含zip等子目录。
在程序中使用Java类库时,必须要把类的整个包路径通过Java语言的import语句导入到程序中。例如,如果在程序中要引入Scanner类,可以将下面的语句加在程序的开始。
import java.util.Scanner;
Java编译器默认为所有的Java程序引入了Java类库的Java.lang 包中所有的类。其中定义了一些常用类,如System、String、Object、Math等。因此我们可以直接使用这些类,而不必显式引入。但使用其他包中的类时,则必须先引入、后使用。不过,也存在一种特殊情况,可以不用导入而直接使用外部包的类,就是使用类的完全限定名称。例如,程序要使用Scanner类,如果省略了导入Scanner的语句,则需要在使用Scanner类的位置使用Java.util.Scanner。
下面是Java程序中常用的类库:
● Java.lang:包含一些Java语言的核心类库,如String、Math、Interger、System和Thread。
● Java.util:包含一些实用工具类,如定义系统特性、日期时间、日历、集合类等。
● Java.io:包含能提供多种输入输出的文件读写类。
● Java:包含执行网络相关操作的类。
● Java.sql:Java操作数据库的一些API。
● Java.text:包含了一些用来处理文本、数字和消息的类和接口。
● java.awt:用来构建和管理Java程序图形用户的界面的类。
● Javax.swing:在awt基础上构建的一套新的图形界面类。
第二小节 System类
System类是Java核心类库之一,提供了标准设备的输入与输出以及系统控制功能。这里说的标准设备是指计算机的显示器、键盘和鼠标,其中显示器是输出设备,键盘和鼠标是输入设备。
System类本身并不支持对设备的读(输入)写(输出)功能。不过System有三个重要的属性err、in、out,System借助这三个属性实现了对设备的读写功能。
其中,err和out用于输出信息。
err是输出错误信息的,错误信息是在程序发生错误时要输出的信息。例如,当你预测一条除法语句可能会发生被零除的错误时,就可以用err输出错误信息;再如,程序应用try—catch语句时,被catch语句捕捉到的错误,在catch语句中就可以用err输出捕捉到的错误信息。
err默认是把错误信息输出到显示器(控制台),也可以通过重定向输出到其它显示设备,也可以输出到文件,可以调用err的setErr方法进行重定向。
out用于输出程序的运行信息,运行信息包括程序对用户的提示信息、程序计算结果等信息。例如,程序提醒用户输入长方形的长度和宽度值;再如,程序计算机长方形面积值,并将计算结果输出到控制台。
out同err一样,默认把运行信息输出到控制台。也可以通过重定向输出到其它显示设备。
err和out提供了print、println、printf等方法用于输出信息,print和println的主要区别是print输出结束后,不添加换行符,下次调用print输出数据时,依然是接上次的位置输出。println输出结束后,添加换行符,下次调用print或println会另起一行输出;printf可以对信息进行格式化输出。
前面介绍了err和out,下面介绍in。
in用于输入信息。程序运行时需要从外部获取数据,数据的输入有人工输入、文件输入、机器输入等多种输入方式。人工可以通过键盘、鼠标、手写等方式输入信息到程序;文件输入是指信息存储在文件中,由程序打开文件直接读取文件内容,例如视频播放器的输入源就是视频文件,视频播放器打开视频文件,读取视频内容并实时播放;机器输入是指由机器识别外部内容,并将识别的内容输入的程序。例如,扫描仪扫描照片,并将识别的照片内容输入到扫描程序,扫描程序再把识别的照片内容存储到照片文件。
in完成从输入源获取数据的功能,in提供了统一抽象的读取方法,以适应不同的输入设备需要。支持输入设备的类需要实现in抽象的读取方法,才能从in获取数据。同时in可以扩展其输入功能,简化输入程序。例如,把in与支持文本扫描的Scanner类关联起来,就可以简化输入程序的编写,下面的语句将in和Scanner关联起来:
Scanner sc = new Scanner(System.in);
第三小节 Scanner类
当程序需要从键盘获取用户输入的命令或数据时,就需要使用到Scanner类,Scanner类是文本扫描类,用于简化输入程序的编写。例如:获取用户输入的长方形的长度和宽度时,就可以通过Scanner类方便地获取。
通过Scanner类获取用户输入时,控制台会一直等待用户的输入,直到用户敲回车键结束,把所输入的内容传给Scanner类,程序要从Scanner类获取输入的内容,则只需要调用Scanner类的nextLine()方法即可。
Scanner需要和System类in属性关联起来,可以方便获取用户从键盘的输入。Scanner通过传入的System.in获取用户输入,并对用户输入的字符进行处理,屏蔽了获取用户输入的复杂操作。
Scanner类提供了多个方法,用于获取用户的输入,主要方法有next和nextLine。next一定要读取到有效字符后才可以用回车键结束输入,对输入有效字符之前遇到的空格键、Tab键或Enter键等结束符,next会自动将其滤掉;nextLine持续接收用户输入,直至用户按下回车键,与next不同的是,nextLine不过滤空格和Tab键。
代码示例:Scanner类的输入操作
了解了类库和基本的输入与输出后,可以回到求长方形面积算法的问题了,算法的第二个步骤是输入长度和宽度,并将长度赋值给num1,宽度赋值给num2,用代码实现算法的1、2步骤:
■ 课程小结
1、Java类库是一组类的集合,包含众多的类。开发者可以直接将这些类集成到代码中,而无需再重写类似功能的代码。如输入与输出功能、文件读写功能、网络功能等。使用Java类库时,开发者需要使用import语句将类库导入到程序中,然后才能使用。Java编译器默认为所有的Java程序引入了Java类库的Java.lang 包中所有的类。其中定义了一些常用类,如System、String、Object、Math等,因此使用这些类时,无需再导入类库。
2、System类是一个非常重要的类,该类提供了标准设备的输入与输出以及系统控制功能。System类有三个非常重要的属性err、out、in,其中err和out是都是输出信息到设备,err和out的区别是err用于程序错误信息的输出,out用于程序运行信息的输出;in是从各类输入设备获取数据,in不能被直接使用,需要和支持输入设备的类关联后才能使用。
3、从键盘获取用户输入的数据时,一般使用Scanner类。Scanner类可以对System.in获取的数据进行预处理,简化开发者对输入数据的处理工作。
■ 思考与练习
1、当程序运行发生错误时,如何在程序中输出错误信息?
2、当程序需要输出相应信息给用户时,如何输出信息?
3、如何从键盘获取用户输入的数据?
- ?
如何用Java制作一个简单数据库
罗安寒
展开
笔者准备上大二,四月时加入了学院一个为期一年的Hadoop开发研究项目小组,暑假绝对是不可错过的学习时期。由于Hadoop 是由Java 编写的,调用API 最好也是用Java,Java的简单使用因此成为我们小组的必修。
我们选择的教材是《Thinking in Java》(Bruce Eckel)和网课《Java4android》(Mars老师)。悄悄告诉你,我《Thinking in Java》截稿时才看了不到200页。
制作一个简单数据库是 《Java4android》中Mars老师留下的作业。我花了三天半完成,700+行。(代码太长,就不一一贴出来了,文末有跳转查看和下载地址)
学习是一个输入和输出的过程,这篇文章就当作我Java入门的奠基,同时可以帮助初学者理解Java这门语言的使用,也欢迎参照这个小项目练练手。
---------------------------------------------------
笔者的这个数据库是基于文本文件的读写储存,原理比较简单。
数据库命令: 首先,数据库有四大基本功能:增删改查(add/delete/update/query),我为了使用方便,在设定这四个命令的同时,增加了“列出全部(show)”和“退出(quit)”。
数据库成员: 数据库每个成员有五个值:与
命令格式:
ADD
DELETE
UPDATE
QUERY
SHOW
QUIT
程序文件纵览:(已展开展示成员与方法)
程序类文件图:(使用Eclipse的Modelgoon插件反向制作UML)
程序关系图:
(我知道挺乱●﹏●)
程序文件各类的作用分析:
Main:显示欢迎界面、调用MainLooper的loop()方法(程序主循环)。
MainLooper:程序主循环、从Input的getInputLine()方法获得命令输入、把输入的字符串传给CheckCmd的check()方法、如果传去check()的值为”QUIT”则跳出循环。
Input:bufferedReader.getInputLine()方法中,调用java.io.BufferedReader的readLine()方法读取整行字符串返回。
Data.txt:存放数据库的文件。
Eng.properties:存放用户交互界面(UI)提示
IOProperty(截图里打错了):利用java.util.Properties的load(InputStreaminStream)方法,读取储存文件键值对。
UserInterface:提供获取UI提示的方法。
User:方便获得、暂存、修改、统一输出成员的值。
UsefulMethod:(实用方法)专门在代码重构时新增的类,供使用的类继承,意在统一管理常用的6个方法。分别是:1、反馈命令成功执行 2、判断字符串是否为数字 3、判断成员的数值value是否符合要求 4、判断新增成员key是否重复 5、把数据库储存文件的内容按照id排序(选择排序法) 6、消除String[]中的null。
CheckCmd:使用String的.split(“ ”)方法拆分命令,检查判断输入命令,若无语法问题即进行相应操作,否则报错。
Action:根据CheckCmd的调用进行相应的操作实现数据库功能。
WriteFile:根据调用的参数把字符串添加或覆盖写入文件。
QueryFile:showAll()方法返回数据库所有的内容,query(inttypeIndex, int operIndex, String args) 根据参数进行相应的搜索,返回所有符合条件的成员。
命令实现详析:
ADD
actAdd(String[] strs):可添加前提:命令长度为6、成员数值value和性别合规、key不重复。否则根据不符的要求相应显示提示。
actAdd(String[] strs):new一个User类,放入成员值,用writeFile.write(user.toString(),true)添加到文件尾部,并执行一次sortData()(文件全内容按id排序)。
DELETE
checkDelete(String[] strs):前提:命令长度为2。判断命令参数是否为id(isNumberic(Stringstr)),并输入到actDELETE()。
actDelete(String[] strs, boolean isId):调用queryFile.showAll()获得文件全部内容并存在String[]中。根据isId循环检索对应key,成立便跳出,把对应字符串赋为””空字符串,并复写在文件上。
UPDATE(设计仅支持salary修改)
checkUpdate(String[] strs):前提:命令长度为4、命令第2部分是salary。判断命令参数是否为id,并输入到actUPDATE()
actUpdate(String[] strs, boolean isId):与DELETE类似,调用queryFile.showAll()获得文件全部内容并存在String[]中。根据isId循环检索对应key,成立便跳出,把对应成员值放在一个user成员内,并修改成员salary值,再复写在文件上。
QUERY
checkQuery(String[] strs):前提:命令长度为4。根据type index{0.
actQuery(int typeIndex, int operIndex, Stringargs):调用queryFile.query(typeIndex, operIndex, args)获取结果并循环输出结果。
query(int typeIndex, int operIndex, Stringargs) :把简化的情况分别检索。思想挺简单,逻辑容易乱,代码也多。
SHOW
checkShow(String[] strs):前提:命令长度为1。直接调用actShow(String[]strs)。
actShow(String[] strs):调用queryFile.showAll()获取全部内容并循环输出。
QUIT
checkQuit():输出“谢谢使用”,并返回-1至MainLooper,跳出循环,程序终结。
Data.txt截图:
Eng.properties截图:
运行效果:(注:亮绿色为键盘输入)
------------------------------------------------------
至此,我把我数据库的结构与实现方式大概展现出来了。
但正如我们的精神领袖Linus Torvalds所说的“Talk is cheap, show me the code.”说多无益,想要自己有大长进,就要多看优秀代码,同时自己多写代码。
在此我放出链接:
直接看代码链接:Java简单数据库 源码展示
下载链接:http://pan.baidu/s/1dE82FJF 密码:jyq0
(包含源码和可运行jar)
欢迎找BUG。
感谢Bruce Eckel 和 Mars老师。
谢谢各位看看官。
- ?
SpreadJS ExcelIO实现服务器端Excel导入导出
嵇若南
展开
SpreadJS在V10版本后推出了纯前端的Excel导入导出,这个功能可以很方便的实现客户端的Excel导入导出,但是如果用户需要导入导出到浏览器端又该怎么办呢?其实纯前端的Excel导入导出同样可以实现服务器端的Excel导入导出。下面让我们来看一下是如何实现的:
本示例的后端使用JAVA语言,通过SpreadJS的前端导出导出与JAVA后端结合,实现分从服务器端导入Excel与导出Excel保存至服务器端这两个功能:
从服务器端导入Excel:
这部分使用纯前端实现,纯前端实现有一个弊端就是,浏览器没有权限访问服务器上工程目录以外的路径,所以需要将服务器端的Excel放入工程目录下。然后下载到前端直接打开,核心代码如下:
导出Excel保存至服务器端:
这部分使用前端导出功能与后端java结合的方式来实现,首先通过前端Excel导出,生成导出文件,然后通过formdata来承载导出文件,之后通过ajax将formdata传至后端java。后端java使用文件操作将文件保存至服务器端。
这里有以下需要注意的地方:
formdata没有办法改变enctype,而我们需要的用entype为multipart/form-data类型的form来承载导出文件。这里需要在jsp页面上创建一个空的form,并将其entype设置为multipart/form-data:
之后js中只需要初始化一个该form的formdata实例即可:
var fd = new FormData(document.forms.namedItem("myform"));
以上就是核心的部分代码以及原理。
了解更多
SpreadJS是 Spread 表格开发系列产品之一。该产品是葡萄城公司出品的一系列功能和 Excel 类似的表格工具,支持桌面、Web 和移动平台开发,用于在应用系统中实现 Excel 导入导出、表格数据录入和编辑等交互功能,并提供灵活的定制能力和丰富的数据可视化效果。
Spread 是目前市面上最接近 Excel 的表格开发工具,无论是界面、函数还是布局,都与 Excel 高度接近,正被华为、东软、中国平安、河海大学、中通快递、普华永道、魔方网表、思源软件等企业应用于项目开发中。
除了纯前端的SpreadJS,该系列产品还包括 .NET 平台可用的Spread Studio,和服务器端批量操作Excel的Spread表格组件,敬请登陆官网了解更多:http://gcpowertools/
关于葡萄城
葡萄城成立于1980年,是全球最大的控件提供商,世界领先的企业应用定制工具、企业报表和商业智能解决方案提供商,为超过75%的全球财富500强企业提供服务。葡萄城于1988年在中国设立研发中心,在全球化产品的研发过程中,不断适应中国市场的本地需求,并为软件企业和各行业的信息化提供优秀的软件工具和咨询服务。
- ?
Java实现文件批量导入导出实例(兼容xls,xlsx)
万恶
展开
1、介绍
java实现文件的导入导出数据库,目前在大部分系统中是比较常见的功能了,今天写个小demo来理解其原理,没接触过的同学也可以看看参考下。
目前我所接触过的导入导出技术主要有POI和iReport,poi主要作为一些数据批量导入数据库,iReport做报表导出。另外还有jxl类似poi的方式,不过貌似很久没跟新了,2007之后的office好像也不支持,这里就不说了。
2、POI使用详解
2.1 什么是Apache POI?
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
2.2 POI的jar包导入
本次讲解使用maven工程,jar包版本使用poi-3.14和poi-ooxml-3.14。目前最新的版本是3.16。因为3.15以后相关api有更新,部分操作可能不一样,大家注意下。
2.3 POI的API讲解
2.3.1 结构
HSSF - 提供读写Microsoft Excel格式档案的功能。XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。HWPF - 提供读写Microsoft Word格式档案的功能。HSLF - 提供读写Microsoft PowerPoint格式档案的功能。HDGF - 提供读写Microsoft Visio格式档案的功能。
2.3.2 对象
本文主要介绍HSSF和XSSF两种组件,简单的讲HSSF用来操作Office 2007版本前excel.xls文件,XSSF用来操作Office 2007版本后的excel.xlsx文件,注意二者的后缀是不一样的。
HSSF在org.apache.poi.hssf.usermodel包中。它实现了Workbook 接口,用于Excel文件中的.xls格式
常用组件:HSSFWorkbook excel的文档对象HSSFSheet excel的表单HSSFRow excel的行HSSFCell excel的格子单元HSSFFont excel字体HSSFDataFormat 日期格式HSSFHeader sheet头HSSFFooter sheet尾(只有打印的时候才能看到效果)样式:HSSFCellStyle cell样式辅助操作包括:HSSFDateUtil 日期HSSFPrintSetup 打印HSSFErrorConstants 错误信息表
XSSF在org.apache.xssf.usemodel包,并实现Workbook接口,用于Excel文件中的.xlsx格式
常用组件:XSSFWorkbook excel的文档对象XSSFSheet excel的表单XSSFRow excel的行XSSFCell excel的格子单元XSSFFont excel字体XSSFDataFormat 日期格式和HSSF类似;
2.3.3 两个组件共同的字段类型描述
其实两个组件就是针对excel的两种格式,大部分的操作都是相同的。
2.3.4 操作步骤
以HSSF为例,XSSF操作相同。
首先,理解一下一个Excel的文件的组织形式,一个Excel文件对应于一个workbook(HSSFWorkbook),一个workbook可以有多个sheet(HSSFSheet)组成,一个sheet是由多个row(HSSFRow)组成,一个row是由多个cell(HSSFCell)组成。
3、代码操作
3.1 效果图
惯例,贴代码前先看效果图
Excel文件两种格式各一个:
代码结构:
导入后:(我导入了两遍,没做校验)
导出效果:
3.2 代码详解
这里我以Spring+SpringMVC+Mybatis为基础
Controller:
Service
3.3 导出文件api补充
大家可以看到上面service的代码只是最基本的导出。
在实际应用中导出的Excel文件往往需要阅读和打印的,这就需要对输出的Excel文档进行排版和样式的设置,主要操作有合并单元格、设置单元格样式、设置字体样式等。
3.3.1 单元格合并
使用HSSFSheet的addMergedRegion()方法
参数CellRangeAddress 表示合并的区域,构造方法如下:依次表示起始行,截至行,起始列, 截至列
3.3.2 设置单元格的行高和列宽
3.3.3 设置单元格样式
1、创建HSSFCellStyle
2、设置样式
3、将样式应用于单元格
3.3.4设置字体样式
1、创建HSSFFont对象(调用HSSFWorkbook 的createFont方法)
2、设置字体各种样式
3、将字体设置到单元格样式
大家可以看出用poi导出文件还是比较麻烦的,等下次在为大家介绍下irport的方法。
导出的api基本上就是这些,最后也希望上文对大家能有所帮助。
学习Java的同学注意了!!!学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群495273252,我们一起学Java!
java实现数据导入导出
-
1、只需3秒快速实现求和
-
2、如何快速填充序号
-
3、如何自动填充序号(公式法)
-
4、数据条的神奇应用
-
5、多文本快速合并
-
6、查找与替换的不同玩法
-
7、快速定位到指定区域
-
8、数据排序、工资条制作
-
9、快速筛选(模糊、精确筛选)
-
10、快速插入空行
-
11、快速删除空行
-
12.快速跳转到天涯海角
-
13、.同时查看两个Excel文件
-
14、用条件格式扮靓报表
-
15、一键插入Excel图表
-
16、批量处理行高、列宽
-
17、利用拆分功能查看数据
-
18、批量录入相同内容
-
19、工作表快速跳转
-
20、批量录入表格模板(精品课程)
-
21、Excel函数与公式的应用、公式循环引用的查找
-
22、IF函数单条件判断同比增长
-
23、用sum函数 格式相同,连续多表数据汇总
-
24、excel快捷键
-
25、VLOOKUP函数——根据销售员匹配销售额
-
26、统计各部门销售总额
-
27、统计指定条件个数
-
28、怎样输入当前日期和时间、星期数
-
29、销售业绩排名
-
30、Sumproduct函数-万能函数(销售额汇总求和)
-
31、根据销售员,地区,商品名称汇总
-
32、批量替换PPT字体
-
33、给销售额数据批量添加万元单位
-
34、一秒快速核对两列数据
-
35、快速定位到指定单元格或区域
-
36、快速制作双行标题工资条
-
37、给你的表格做个瘦身
-
38、快速打开常用的Excel文件
-
39、快速打开多个Excel文件
-
40、利用创建组—快速隐藏/展开多列数据
-
41、快速制作下拉菜单
-
42、复制粘贴表格,如何保留数据源列宽格式一致?
-
43、两列数据位置互换
-
44、1秒钟扮靓报表——如何实现表格隔行换色
-
45、快速删除重复记录——保留唯一值
-
46、快速向下填充、向右填充,文本或公式
-
47、给Excel文件添加密码
-
48、插入带图片的批注
-
49、输入公式后不计算?
-
50、如何设置单元格缩进
-
51、快速解决Excel表格总显示货币格式
-
52、批量添加万元单位
-
53、你会四舍五入么?
-
54、用RAND函数机选彩票
-
55、冻结首行你会么?
-
56、超链接的高级应用
-
57、IFERROR函数-屏蔽错误值
-
58、批量填充颜色
-
59、录入数据
-
60、快速输入工号
-
61、快速行列转置
-
62、自定义缩放界面
-
63、多个单元格同时输入
-
64、如何计算立方米?
-
65、快速制作双行标题工资条
-
66、输入带方框的√和×
-
67、快速将姓名对齐
-
68、快速输入性别
-
69、按单位职务排序
-
70、自动计算合同到期日期
-
71、计算时间间隔
-
72、日期和时间的拆分
-
73、快速处理不规范的日期格式
-
74、快速填充合并单元格
-
75、效率加倍的快捷键
-
76、快速复制表格和对象
-
77、快速创建工作表副本
-
78、快速复制序列号
-
79、快速显示公式
-
80、多个单元格同时输入
-
81、快速调整显示比例
-
82、快速自动填充
-
83、快速填充(Ctrl+E)
-
84、Ctrl与数字键结合
-
85、快速将多列数据整理为1列
-
86、快速将1列数据拆分为多列
-
87、快速定位公式
-
88、快速录入数据
-
89、快速累计求和
-
90、身份证号码显示为0怎么办?
-
91、快速制作斜线表头
-
92、文本竖向显示
-
93、神奇的监视窗口
-
94、不一样的格式刷
-
95、快速美化图表
-
96、快速生成当前日期
-
97、快速找出循环引用
-
98、快速提取信息
-
99、二维表快速转换为一维表
-
100、快速多表合并