JSON(Java Script Object Notation),是一种语言无关的数据交换格式。 JSON插件是Structs 2 的Ajax插件,通过利用JSON插件,开发者可以很方便,灵活的利用Ajax进行开发。
Json是一种轻量级的数据交换格式,JSon插件提供了一种名为json的Action ResultType 。一旦为Action指定了该结果处理类型,JSON插件就会自动将Action里的数据序列化成JSON格式的数据,并返回给客户端物理视图的JavaScript。简单的说,JSON插件允许我们在JavaScript中异步的调用Action。
而且Action不需要指定视图来显示Action的信息显示而是由JSON插件来负责具体将Action里面具体的信息返回给调用页面。Json的数据格式可简单如下形式: person = { name: ‘Jim’,age: 18,gender: ‘man’}。
如果action的属性很多,我们想要从Action返回到调用页面的数据。这个时候配置includeProperties或者 excludeProperties拦截器即可。而这2个拦截器的定义都在struts2的json-default包内,所以要使用该拦截器的包都要继承自json-default。
<struts>
<constant value="spring" name="struts.objectFactory" />
<include file="struts-admin.xml"></include>
<package name="default" extends="json-default">
<action class="com.person.PersonAction" name="person" method="view">
<result type="json">
<param name="includeProperties">person\.name,persoon\.age,person\.gender </param>
</result>
</action>
</package>
</struts>
相关介绍:
Spring 官方英文:http://static.springsource.org/spring-security/site/docs/3.1.x/reference/security-filter-chain.html#d4e1307
中文翻译:http://www.family168.com/tutorial/springsecurity3/html/web-infrastructure.html#d0e2828
更多介绍:http://www.family168.com/oa/springsecurity/html/ch101-filters.html
之前介绍了一个Swing做的原子钟的效果 “Swing Nixieclock(原子钟)效果”,作者放出了制作 Swing原子钟 制作的主要元素 – 原子钟的制造过程。

想看制作过程的移步这里:
先通过绘图工具,绘出原型,绘制过程以及绘制时的参数,要在Swing中使用。
将原型绘制过程中的一些数据,以Java Code 的形式在Swing中体现出来,步骤和通过绘图工具绘制时差不多,一步步来。
在JavaEye上看的这个,转发一下,原文:http://www.javaeye.com/news/13151
Gerrit 受到了这些设计的启发,尝试着使用Swing创造出了NixieClock(原子钟)效果。
*首先,在Fireworks中创建了一个原型

*第二步是建立一个JavaBean并将其转成Swing,这个步骤要花费很多时间
*第三步是建立一个包含时钟逻辑的JFrame和6个nixie number的组件
结果如下:

下载NixieClock:http://www.jug-muenster.de/wp-content/uploads/2010/01/NixieClock.zip
分两部分:一部Java Net(大部分来自Java Doc), 一部分XML Parser, 通过一个Twitter的例子来描述简单的使用情况。
java.net 包的概述:
java.net包大致可分为两部分:
在整个 java.net API 中,地址或者用作主机标识符或者用作套接字端点标识符。
InetAddress 类是表示 IP(Internet 协议)地址的抽象,它拥有两个子类:
Inet4Address。Inet6Address。但是,在大多数情况下,不必直接处理子类,因为 InetAddress 抽象应该覆盖大多数必需的功能。
套接字是在网络上建立机器之间的通信链接的方法。java.net 包提供 4 种套接字:
Socket 是 TCP 客户端 API,通常用于将 (java.net.Socket.connect(SocketAddress)) 连接到远程主机。ServerSocket 是 TCP 服务器 API,通常接受 (java.net.ServerSocket.accept) 源于客户端套接字的连接。DatagramSocket 是 UDP 端点 API,用于发送和接收 java.net.DatagramPackets。MulticastSocket 是 DatagramSocket 的子类,在处理多播组时使用。使用 TCP 套接字的发送和接收操作需要借助 InputStream 和 OutputStream 来完成,这两者是通过 java.net.Socket.getInputStream 和 java.net.Socket.getOutputStream 方法获取的。
java.net 包中的许多类可以提供更加高级的抽象,允许方便地访问网络上的资源。这些类为:
URI 是表示在 RFC 2396 中指定的统一资料标识符的类。顾名思义,它只是一个标识符,不直接提供访问资源的方法。URL 是表示统一资源定位符的类,它既是 URI 的旧式概念又是访问资源的方法。URLConnection 是根据 URL 创建的,是用于访问 URL 所指向资源的通信链接。此抽象类将大多数工作委托给底层协议处理程序,如 http 或 ftp。HttpURLConnection 是 URLConnection 的子类,提供一些特定于 HTTP 协议的附加功能。建议的用法是使用 URI 指定资源,然后在访问资源时将其转换为 URL。从该 URL 可以获取 URLConnection 以进行良好控制,也可以直接获取 InputStream。
下面是一个示例:
URI uri = new URI("http://java.sun.com/");
URL url = uri.toURL();
InputStream in = url.openStream();
抽象类 URLConnection 是所有表示应用程序与 URL 之间通信链路的类的超类。该类的实例可以用来对由 URL 引用的资源进行读取和写入操作
HttpURLConnection 仅是支持了 HTTP 特定功能的 URLConnection
openConnection 方法产生一连接对象。connect 方法,实现对远程对象的实际连接。通过如下的方法修改设置参数:
通过使用如下的方法修改一般请求属性:
AllowUserInteraction 和 UseCaches 参数的缺省值可以通过使用 setDefaultAllowUserInteraction 和 setDefaultUseCaches 方法来设置。 而一般请求属性的缺省值可以通过方法 setDefaultRequestProperty 来设置 。
上面的每个 set 方法都有相应 get 方法来获取参数和一般请求属性的值。可用的特定参数和一般请求属性是特定于协议的。
对远程对象的连接完成后,用下列方法访问报头域和内容:
确认报头域能够被频繁访问。方法:
提供对这些域的便利访问。 getContentType 方法由 getContent 方法调用以确定远程对象的类型; 子类来覆盖方法 getContentType 可能是有利的。
下面是一个通过Twitter API去获信息的demo:
URL url = new URL("http://t.bbercn.com/statuses/user_timeline.xml");
String username = (String) params[0];
String password = (String) params[1];
String user_paw = username + ":" + password;
String encoding = "Basic " + Base64Converter.encode(user_paw.getBytes());
URLConnection uc = url.openConnection();
uc.setRequestProperty("Authorization", encoding);
InputStream content = (InputStream) uc.getInputStream();
剩下的工作就是对InputStream 进行本地处理,Twitter返回的是XML,那么我们下面就对XML进行解析,获取我们要获取的信息。
关于 xml 解析的工具有很多,具体可以看这里:http://www.open-open.com/31.htm 罗列的一些。
下面通过Commons-Digester来处理上面我们获取的InputStream
public class ParseTools {
private List statuses = new ArrayList<Status>();
public List<Status> getStatuses() {
Collections.sort(statuses);
return statuses;
}
public void parseStatus(InputStream stream) throws IOException, SAXException {
Digester digester = new Digester();
digester.setValidating(false);
digester.push(this);
digester.addObjectCreate("statuses/status", Status.class);
//status
digester.addBeanPropertySetter("statuses/status/id");
digester.addBeanPropertySetter("statuses/status/created_at");
digester.addBeanPropertySetter("statuses/status/text");
digester.addBeanPropertySetter("statuses/status/source");
digester.addBeanPropertySetter("statuses/status/truncated");
digester.addBeanPropertySetter("statuses/status/in_reply_to_status_id");
digester.addBeanPropertySetter("statuses/status/in_reply_to_user_id");
digester.addBeanPropertySetter("statuses/status/favorited");
digester.addBeanPropertySetter("statuses/status/in_reply_to_screen_name");
//user
digester.addObjectCreate("statuses/status/user", User.class);
digester.addBeanPropertySetter("statuses/status/user/id");
digester.addBeanPropertySetter("statuses/status/user/name");
digester.addBeanPropertySetter("statuses/status/user/screen_name");
digester.addBeanPropertySetter("statuses/status/user/description");
digester.addBeanPropertySetter("statuses/status/user/location");
digester.addBeanPropertySetter("statuses/status/user/profile_image_url");
digester.addBeanPropertySetter("statuses/status/user/url");
digester.addBeanPropertySetter("statuses/status/user/isProtected");
digester.addBeanPropertySetter("statuses/status/user/followers_count");
digester.addBeanPropertySetter("statuses/status/user/friends_count");
digester.addSetNext("statuses/status/user", "setUser");
digester.addSetNext("statuses/status", "addStatuses", Status.class.getName());
digester.parse(stream);
}
public void addStatuses(Status status) {
Status d = new Status();
d.setId(status.getId());
d.setCreated_at(status.getCreated_at());
d.setFavorited(status.isFavorited());
d.setText(status.getText());
d.setSource(status.getSource());
d.setTruncated(status.isTruncated());
d.setIn_reply_to_screen_name(status.getIn_reply_to_screen_name());
d.setIn_reply_to_status_id(status.getIn_reply_to_status_id());
d.setIn_reply_to_user_id(status.getIn_reply_to_user_id());
d.setUser(status.getUser());
getStatuses().add(d);
}
}
由于最近另一个项目的启动,工作方面基本上是掐着时间在忙,所以周主题的任务就只能稍微往后推一周了。
预计本周四结合公司的培训内容,出一个有关JQuery的入门介绍,这个内容顺便就补给上周的周主题。
顺便预告下:接下来这周和下周会整理有关Java.Net包下一些常用类的使用,包括HttpClient的使用,以及XML Parser方面的汇总。
选择这个主题,是因为上周公司刚好做了一个有关“Beginning Java AWT and Swing” 的培训,借此机会正好总结一下这方面的使用技巧。对于Swing界面方面的研究,我仅仅是应用而已,公司里有几位同事在这方面的研究比较深,这块的应用和使用技巧分两部分, 一部分是Swing 使用本身的,另一部分是Design工具NetBeans的,如果是刚入门建议从这里看起:Creating a GUI With JFC/Swing。
随着Java 6对于Swing性能的改进,Swing的运行速度已经开始得到了大大的提高,看看NetBeans就知道了,NetBeans就是Swing开发的,如果你跑Swing很慢,很耗资源,那么应该从自己的程序上找找问题,推荐使用NetBeans自带的Profile查找原因,教程在这里 – Profile Introduce 。
用Swing做企业应用时,LookAndFeel的选择和使用是决定这个项目能否被客户接受的一个很大因素,即要好看,又要考虑跨平台的兼容性,必要时自己还得设计部分LookAndFeel, 可以看看这里提供的一些开源LookAndFeel:http://www.open-open.com/61.htm 和http://www.javootoo.com/。
切换LookAndFeel:UIManager.setLookAndFeel(LookAndFeelName); SwingUtilities.updateComponentTreeUI(frame); frame.pack();
举个例子:之前我们项目中有一个地方,当打开程序时,会初始化几十个甚至成百个JPanel,这显然成为程序启动时慢的一个因素,也导致了用户体验的降低,这些JPanel完全可以在程序启动后再根据用户的需要去初始化,因为用户打开程序时这些Panel不是必须看到的。
比如Button的高度,进度条的高宽等,也可以通过UIManager给系统组件设置统一属性,比如统一设定Button的间距和字体:
UIManager.put("Button.margin", new Insets(2, 5, 2, 5)); UIManager.put("Button.font", new Font("宋体", Font.PLAIN, 13));
用Swing做的都是界面的东西,如果界面假死或者用户等待事件太长,那么用户体验必然是不好的,这里就需要用到多线程的使用了,当界面处理一个请求时,不能让界面假死了,需要后台另一个线程去做处理,然后将结果返回到Swing线程,这块可以看看SwingWorker的介绍。
布局管理器的使用在Swing里面是比较重要的,它直接决定了你界面的显示效果,也是比较难用的一块,不好举例子,建议多了解每个布局管理器的使用场景。
在Swing组件的使用中除了布局管理器,估计就数JTable和JTree的使用稍微有点麻烦了,下面我就分享一些实际项目中JTable的一些实例,关于JTree,可以点这里:JTree 经验 总结 。
JTable相关
1、自定义表头排序
TableRowSorter rs = (TableRowSorter) table.getRowSorter(); Comparator<Integer> intComparator = new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; rs.setComparator(3, intComparator);2、自定义Table Renderer
public class CommonTableCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean cellHasFocus, int row, int column) { JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, cellHasFocus, row, column); //表格的奇数偶数行交叉颜色显示 if (!isSelected) { if (row % 2 == 0) { comp.setBackground(UIConsts.HIGHLIGHTER_COLOR); } else { comp.setBackground(Color.white); } } //table column里面显示图标和对齐方式 switch (column) { case PaperTableModel.STATUS_COLUMN: switch ((EntityStatus) value) { case VALID: comp.setIcon(ENABLED_ICON); setHorizontalAlignment(JLabel.LEADING); break; case DISABLED: comp.setIcon(DISABLED_ICON); setHorizontalAlignment(JLabel.CENTER); break; } break; default: comp.setIcon(null); break; } return comp; } }3、自定义Table列宽
TableColumnModel colModel = table.getColumnModel(); colModel.getColumn(0).setPreferredWidth(70); colModel.getColumn(1).setPreferredWidth(55); colModel.getColumn(2).setPreferredWidth(120);4、禁止Table列拖动
table.getTableHeader().setReorderingAllowed(false);5、单选表格设置
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);6、设置表头默认支持排序
table.setAutoCreateRowSorter(true);7、设置列不可随容器组件大小变化自动调整宽度
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);8、固定Table上的某些列不滚动
这个需求是这样的,比如Table上左边有部分数据,是后面数据所共有的属性,那么当后面数据很多时,显示不下会出现滚动条,但是滚动时又不想让左侧的共有属性动,只滚动右侧的数据部分。
实现原理是:scrollPane里面放置一个表格,然后在scrollPane的左上角放置以共有属性的部分为Model的表格,剩下的右侧就是剩余的纯数据表格。
最终效果就是表格左侧的列锁定了,右侧数据出现滚动条时,可以滚动,但左侧不动。
核心代码:比如有HeaderTable和ReportTable, 其中ReportTable是放置在一个ScrollPanel里面,Model是所有数据的Model,将左侧的数据和右侧的数据分开//找到主表所在的scrollPane JScrollPane scrollPane = (JScrollPane) SwingUtilities. getAncestorOfClass(JScrollPane.class, reportTable.getTable()); //中间处理headerTable的数据和reportTable剩余的数据 //将新表HeaderTable放在scrollPane的左上角 scrollPane.setRowHeaderView(headerTable.getTable()); scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, headerTable.getTable().getTableHeader());9、Table上的直接编辑功能
两点:
1、重写 public boolean isCellEditable(int row, int columnIndex) 方法,定义可编辑的行列。
2、重写 public void setValueAt(Object obj, int rowIndex, int columnIndex) 方法,拿到原来的对象,设置新的对象值。10、Table的Excel导出功能
表格上的Excel导出功能还是比较实用的功能,企业应用一般都会用到,这里提供相关代码
try { WritableCellFormat titleFormat = new WritableCellFormat( new WritableFont(WritableFont.createFont("黑体"), 16, WritableFont.NO_BOLD)); titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐 titleFormat.setAlignment(Alignment.CENTRE); // 水平对齐 titleFormat.setWrap(true); // 是否换行 WritableCellFormat headerFormat = new WritableCellFormat(); headerFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条 headerFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐 headerFormat.setAlignment(Alignment.CENTRE); // 水平对齐 headerFormat.setWrap(true); // 是否换行 WritableCellFormat countFormat = new WritableCellFormat( new NumberFormat("0.000")); countFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条 countFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐 countFormat.setAlignment(Alignment.RIGHT); // 水平对齐 countFormat.setWrap(true); // 是否换行 WritableCellFormat moneyFormat = new WritableCellFormat( new NumberFormat("0.00")); moneyFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条 moneyFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐 moneyFormat.setAlignment(Alignment.RIGHT); // 水平对齐 moneyFormat.setWrap(true); // 是否换行 WritableCellFormat intFormat = new WritableCellFormat( new NumberFormat("0")); intFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条 intFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐 intFormat.setAlignment(Alignment.RIGHT); // 水平对齐 intFormat.setWrap(true); // 是否换行 WritableWorkbook book = Workbook.createWorkbook(exportFile); WritableSheet sheet = book.createSheet("综合统计报表", 0); int titleRow = 0; int headerRow = 3; int dataRow = 5; sheet.mergeCells(0, titleRow, model.getColumnCount() - 1, titleRow); Label titleLab = new Label(0, titleRow, tableTitleTxfd.getText(), titleFormat); sheet.addCell(titleLab); //生成表头 for (int j = 0; j < model.getColumnCount(); j++) { sheet.mergeCells(j, headerRow, j, headerRow + 1); Label lab = new Label(j, headerRow, model.getColumnName( j), headerFormat); sheet.addCell(lab); } for (int row = 0; row < model.getRowCount(); row++) { for (int col = 0; col < model.getColumnCount(); col++) { Object obj = model.getValueAt(row, col); if (obj instanceof String) { Label lab = new Label(col, dataRow + row, (String) obj, headerFormat); sheet.addCell(lab); } else if (obj instanceof Integer) { Number labelN = new Number(col, dataRow + row, (Integer) obj, intFormat); sheet.addCell(labelN); } else { Label lab = new Label(col, dataRow + row, "", headerFormat); sheet.addCell(lab); } } } //生成表尾 int footerRow = dataRow + model.getRowCount() + 1; int step = (int) (((double) (model.getColumnCount() - 2) / 3) + 1); Label footerLab = new Label(0, footerRow, "部门负责人:"); sheet.addCell(footerLab); footerLab = new Label(step, footerRow, "制表:" + creatorTxfd.getText()); sheet.addCell(footerLab); footerLab = new Label(model.getColumnCount() - 2, footerRow, NazcaFormater.getSimpleDateString(new Date())); sheet.addCell(footerLab); sheet.setColumnView(0, 16); sheet.setRowView(titleRow, 600); book.write(); book.close(); //导出成功 } catch (Throwable ex) { //导出报表失败 ex.printStackTrace(); }11、Table的打印功能
打印这块,之前已经提过,可以参考之前的文章 JTable Print
12、在Table上选择多行
int rowcounts=table.getSelectedRows().length; if(rowcounts>1) int[] rows=table.getSelectedRows(); for(int i=0;i<rows.length;i++){ String value=(String) tableModel.getValueAt(i, 1); } }
这里说NetBeans,主要是因为目前Swing开发方面,还没有哪个IDE能胜过NetBeans。
一、NetBeans的配置
1、配置为英文,大部分时间我们下载的都是中文的版本,可以通过在/$NetBeans_HOME/etc/netbeans.conf中添加 –locale en_US, 让启动时显示为英文,这个之前也有文章介绍:Netbeans 英文界面 和 最简单的Netbeans中英文切换
2、优化配置可以看之前介绍的这篇文章,就不重复了:Netbeans 6.5 优化建议二、经验分享
1、Swing的Debug虽然被很多人说不好用,但是在用NetBeans时,多用Debug可以提高效率,因为Debug模式下的修改,大部分只要点击应用,就可以不用重启项目而看到效果。
2、很好用的快捷键和快速补齐(限Windows + Linux下,如果在Mac下改成 ⌘ 试试),如:快捷键: Ctrl+R Rename Alt+Enter Fix Error(Eclipse Ctrl+1) Alt+Shift+F Quick Format Alt+Shift+I Fix Import F9 Build File F6 Run Main Project Shift+F6 Run File Ctrl+| Insert Code 快速补齐(英文输入状态下,输入完后按Tab键,也可以自己配置为其他键,在Options - Editor - Code Templates下): psvm public static void main sout System.out.println im implements Psfs public static final String psfi private static final String fore for($ : $){} fori for(int i = 0; i < arr.length; i++){} forl for(int i = 0; i < list.size(); i++){}三、插件分享
我们都知道NetBeans上的插件很多,可以说NetBeans正是因为这些插件才强大起来,支持的功能也更多了。分享的这几个插件是平时工作时,可以显著提高效率的,不好的不推荐,你如果有好的也别忘记分享下。1、Path Tools – 可以直接查找到类或者文件夹所在的磁盘位置,基本是我每次装完NetBeans的后第一个装的插件。
2、SQE(Software Quality Environment) – 是最近同事刚刚推荐的一个插件,看名字就知道了,是一个类似Firebug的插件,可以发现程序中存在的一些显著的错误,很不错。
3、UUID Generator - 同事写的一个快速生成UUID的插件。
4、SwingX 插件 – 用来添加一些SwingX组件的。
5、iReport – 打印报表用的插件,结合JasperReport使用。
这是本博客开始周主题的第一个主题,周主题计划按自然周为标记,记录一年内每周的关注主题,这样至少可以提醒自己哪个周的没有写了。
对于JPA不熟悉的朋友可以先看看这里:百度百科之JPA 里面介绍了JPA的起源,优势,厂商等。
本文是由网上其他网友的经验和自己的经验总结而成,个人能力有限,不免有错误之处,如有误导之地恳请指正。欢迎大家提出宝贵意见,以便完善。

1. 新建态(New):新创建的实例对象,没有持久化主键。
简单讲就是你刚new出来的对象,谁也管不着的。
2. 受控态(Managed):在持久化上下文中受管理的对象;
先理解两个概念持久化主键和持久化上下文:持久化上下文是由与该上下文相关联的 EntityManager 实例管理的一组实体实例,关键词是EntityManager, 新创建的实体尚未被托管于持久化上下文中,EntityManager无法对它进行管理。EntityManager对持久化上下文中的实体进行管理,必然通过主键去查找实体对象,这个主键就是持久化主键。
3. 游离态(Detached):游离于持久化上下文之外的实例对象;
4. 删除态(Removed):被删除的实例对象。
这些状态通过调用EntityManager的接口方法进行相互迁移
void persist(Object entity)
- 通过persist()方法,新建状态将转换为受控状态。这意谓着当persist ()方法所在的事务提交时,实体的数据将保存到数据库中。
- 如果实体已经被持久化,那么再调用persist()操作,会抛出异常 Duplicate entry。
- 如果对一个已经删除的实体调用persist()操作,删除态的实体又转变为受控态,实体的数据将保存到数据库中。
- 如果persist的是一个游离实体(即上下文中没有它),而上下文中又没有它的受管版本,数据库却有这个实体,那么会抛出异常 Duplicate entry;
- 如果persist的是一个游离实体(即上下文中没有它),而上下文中却有它的受管版本,数据库中也有了这个实体,那么EntityManager在persist它的时候就会抛出异常:javax.persistence.EntityExistsException
- 在一个实体上调用persist()操作,将广播到和实体关联的其他实体上,执行相应的级联持久化操作;
void remove(Object entity)
- 通过remove()方法删除一个受控的实体;
- 如果实体声明为级联删除(cascade=REMOVE 或者cascade=ALL ),被关联的实体也会被删除;
- 在一个新建状态的实体上调用remove()操作,将被忽略;
- 如果在游离实体上调用remove()操作,将抛出 IllegalArgumentException,相关的事务将回滚;
- 如果在已经删除的实体上执行remove()操作,也会被忽略
T merge(T entity)
- 将一个游离态的实体持久化到数据库中,并转换为受控态的实体;
- Merge一个游离版本,同时上下文中却有它的受管版本,那么返回的是受管版本,数据库中的数据更新
Query createQuery(String qlString)
- 根据JPA的查询语句创建一个查询对象Query
T find(Class entityClass, Object primaryKey)
- 以主键查询实体对象,entityClass是实体的类,primaryKey是主键值
1. EntityManager对象的事务管理方式有两种,分别为JTA和RESOURCE_LOCAL,即Java Transaction API方法和本地的事务管理。JPA中的事务类型通过persistence.xml文件中的“transaction-type”元素配置。JTA事务只能运行在J2EE的环境中,即EJB容器中和Web容器中;而在J2SE环境中只能使用RESOURCE_LOCAL管理事务。
2. 注意OneToMany,ManyToOne,ManyToMany三种关系时的参数配置.
3. Merge也有Persist的功能,数据库中有就merge,没有添加。
4. 注意Transaction的使用,不要一个方法中有几个Transaction。
5. 正确使用Eager和Lazy能显著提交效率。
6. 使用persist,只需注意操作的对象要么是new,要么是受管的,否则肯定出问题。
7. 使用merge,基本上无论如何都不会抛异常,但后续的操作必须针对该方法返回的新受管对象进行操作,否则肯定出问题。
1. http://www.oracle.com/technology/products/ias/toplink/jpa/index.html
2. http://baike.baidu.com/view/1036852.htm?fr=ala0
3. http://java.sun.com/javaee/technologies/persistence.jsp
4. http://pz0513.blog.51cto.com/443986/113098
==本文谢绝转载,谢谢==
这几天在做关于JTable的打印工作,项目中客户需要直接将JTable打印出来,之前这方面工作做的比较少,经过这几天的研究,稍微有些积累,现在分享一下。
JTable打印目前用的比较多的还是JasperReport来实现的,JasperReport开源免费,但是不是特别好用,这也是为什么JasperReport免费用,但是培训是收费的。
不过常用的一些JTable的打印实现起来也还好了,只是复杂的稍微有些麻烦,可以看看我之前介绍的一篇入门文章:JasperReport 个人使用的一些经验
这里主要分享的是通过Swing 打印的积累,JasperReport常用的简单的打印没问题,但是遇上比较复杂的表单,比如合成表头等,就稍微有点麻烦,当然也有可能是自己没有找到JasperReport的处理方法,要是有朋友知道欢迎分享下。
通过Swing来绘制,应该是无奈的一步,不过通过这无奈的一步,和同事的帮助下,却学习到了不少这方面的知识,尤其是Swing绘制方面的。
下面的代码是我抽出来的一个比较通用的,基于TableModel的表格打印,普通表头,不带合成表头的,如果Table Model不一样,那么自己就需要改改了。
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.math.BigDecimal;
import java.text.NumberFormat;
import javax.swing.JTable;
import javax.swing.table.TableModel;
/**
*
* @author xiaoquan
*/
public class SwingCommonPrinitTools implements Printable {
private TableModel model = null;
private String info;
private int totalRow = 0;
private static final int LEFT = 0;
private static final int RIGHT = 1;
private static final int CENTER = 2;
private static final int AUTO = 3;
public void printTable(TableModel model,
String info) {
this.model = model;
this.info = info;
totalRow = model.getRowCount();
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(this);
if (printJob.printDialog()) {
try {
printJob.print();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private static final double paper_offset_x = 20;
private static final double paper_offset_y = 20;
private static final double title_time_margin = 10;
private static final double time_body_margin = 2;
private static final double cell_padding_y = 3;
private static final double cell_padding_x = 2;
private static final double body_btm_margin = 20;
private static final double body_cell_height = 20;
private static final Font title_font = new Font("黑体", Font.PLAIN, 18);
private static final Font time_font = new Font("Dialog", Font.PLAIN, 10);
private static final Font body_font = new Font("Dialog", Font.PLAIN, 10);
@Override
public int print(Graphics g, PageFormat pf, int pageIndex) throws
PrinterException {
//纸张宽
double pageWidth = pf.getImageableWidth();
//纸张高
double pageHeight = pf.getImageableHeight();
//打印的内容起始X
double pageStartX = pf.getImageableX();
//打印的内容起始Y
double pageStartY = pf.getImageableY();
//表头高
double tableHeadH = 0;
//Cell高
double cellH = 0;
//计算表头高度和单元格高度
g.setFont(body_font);
FontMetrics cellFm = g.getFontMetrics();
cellH = cellFm.getHeight() + cell_padding_y * 2 + 1;
tableHeadH = cellH * 2;
//计算Title以及其位置
String title = info;
g.setFont(title_font);
FontMetrics titleFm = g.getFontMetrics();
int titleW = titleFm.stringWidth(title);
//表底和表头文字属性
g.setFont(time_font);
FontMetrics btmFm = g.getFontMetrics();
FontMetrics timeFm = g.getFontMetrics();
//表格以上的Margin
double tableTopMargin = paper_offset_y + titleFm.getHeight() +
title_time_margin + timeFm.getHeight() + time_body_margin;
//表格每列的最大宽度
double[] cellColMaxWidths = caculateTableCellWidth(model, cellFm);
//当前Page的数据容量高度-不包括表头和表尾
double currentPageDataCapacityHeight = pageHeight - tableTopMargin -
tableHeadH - btmFm.getHeight() - body_btm_margin - 1;
//当前Page的数据容量
int currentPageBodyCapacityRows = (int) (currentPageDataCapacityHeight /
cellH);
//Y方向的分页数量
int pagesY = 0;
if (model.getRowCount() % currentPageBodyCapacityRows == 0) {
pagesY = (int) (model.getRowCount() /
currentPageBodyCapacityRows);
} else {
pagesY = (int) (model.getRowCount() /
currentPageBodyCapacityRows) +
1;
}
//当前页数大于总页数时不打印
if (pageIndex + 1 > pagesY) {
return NO_SUCH_PAGE;
}
//绘制Title
g.setFont(title_font);
g.drawString(title, (int) (pageStartX +
(pageWidth - titleW) / 2), (int) (pageStartY +
paper_offset_y +
titleFm.getAscent()));
//绘制区域移动到新的(0,0)点
g.translate((int) (paper_offset_x + pageStartX), (int) (tableTopMargin +
pageStartY));
int currentX = 0, currentY = 0;
//绘制第一张表
//绘制表头
g.setFont(time_font);
String time = "表头: " + info;
g.drawString(time, currentX, currentY);
currentY += 5;
//绘制单一表头
for (int i = 0; i < model.getColumnCount(); i++) {
double width = cellColMaxWidths[i];
double height = tableHeadH;
String name = model.getColumnName(i);
drawCell(g, name, currentX, currentY, (int) width,
(int) height, CENTER);
currentX += width;
}
//绘制数据
currentX = 0;
currentY = (int) tableHeadH;
//当前Page的数据容量
int rightCellX = 0;
int yIndex = pageIndex;
int startRow = currentPageBodyCapacityRows * yIndex;
int endRow = (currentPageBodyCapacityRows * (yIndex + 1)) >
totalRow
? totalRow
: (currentPageBodyCapacityRows * (yIndex + 1));
for (int row = startRow; row < endRow; row++) {
//绘制单项表头下面的数据
for (int i = 0; i < model.getColumnCount(); i++) {
double width = cellColMaxWidths[i];
double height = body_cell_height;
Object value = model.getValueAt(row, i);
drawCell(g, value, currentX, currentY, (int) width,
(int) height, AUTO);
currentX += width;
rightCellX = currentX;
}
currentX = 0;
currentY += cellH;
}
//绘制闭合线,下面和右侧两条
g.drawLine(currentX, currentY, rightCellX, currentY);
g.drawLine(rightCellX, 5, rightCellX, currentY);
drawBottomInfo(pageIndex, pagesY, currentY, g, (int) pageWidth);
return PAGE_EXISTS;
}
private void drawBottomInfo(int pageIndex, int pagesY,
int currentY, Graphics g, int pageWidth) {
if (pageIndex + 1 == pagesY) {
//绘制底部信息
int btmX = 0;
int btmY = currentY + 20;
g.drawString("负责人:", btmX, btmY);
g.drawString("制表:", pageWidth / 3, btmY);
FontMetrics fm = g.getFontMetrics();
int dataWidth = fm.stringWidth("日期: 2009/10/26");
g.drawString("日期:", pageWidth - dataWidth, btmY);
}
}
/**
* 计算最大列宽
* @param cellFm
* @return
*/
private double[] caculateTableCellWidth(
TableModel model,
FontMetrics cellFm) {
//表格每列的最大宽度
double[] cellColMaxWidths = new double[model.getColumnCount()];
//计算表头每列最大宽度
double[] headerColMaxWidths = new double[model.getColumnCount()];
for (int i = 0; i < model.getColumnCount(); i++) {
String name = model.getColumnName(i);
headerColMaxWidths[i] = cellFm.stringWidth(name) + cell_padding_x *
2 + 1;
}
//没有数据时,表头每列的最大宽度就是表格每列的最大宽度
cellColMaxWidths = headerColMaxWidths;
//算数据每列的最大宽度和表头每列最大宽度对比
for (int j = 0; j < model.getRowCount(); j++) {
for (int i = 0; i < model.getColumnCount(); i++) {
//做些数据类型的判断
Object value = model.getValueAt(j, i);
if (value instanceof BigDecimal) {
value = ((BigDecimal) value).doubleValue();
}
String text = "";
if (value != null) {
text = value.toString();
}
double temp = cellFm.stringWidth(text) + cell_padding_x * 2 + 1;
if (cellColMaxWidths[i] < temp) {
cellColMaxWidths[i] = temp;
}
}
}
return cellColMaxWidths;
}
/**
* 绘制单元格及里面的文字
* @param g
* @param value
* @param x
* @param y
* @param width
* @param height
*/
private static void drawCell(Graphics g, Object value, int x, int y,
int width,
int height, int locate) {
g.drawLine(x, y, x + width - 1, y);
g.drawLine(x, y, x, y + height - 1);
FontMetrics fm = g.getFontMetrics();
if (value == null) {
value = "";
}
switch (locate) {
case 0:
//居左
g.drawString(value.toString(), (int) (x + cell_padding_x), y +
(height - fm.getHeight()) / 2 + fm.getAscent());
case 1:
//居右
g.drawString(value.toString(),
(int) (x +
(width - fm.stringWidth(value.toString()) + width -
fm.stringWidth(value.toString()) - cell_padding_x) /
2), y +
(height - fm.getHeight()) / 2 + fm.getAscent());
case 2:
//居中
g.drawString(value.toString(), x + (width - fm.stringWidth(
value.toString())) / 2, y + (height -
fm.getHeight()) / 2 + fm.getAscent());
case 3:
//自动判断
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumFractionDigits(2);
formatter.setMaximumFractionDigits(2);
//根据数据类型左对齐还是右对齐绘制还是居中对齐
if (value instanceof BigDecimal) {
//居右
value = ((BigDecimal) value).doubleValue();
value = formatter.format(value);
g.drawString(value.toString(),
(int) (x +
(width - fm.stringWidth(value.toString()) + width -
fm.stringWidth(value.toString()) - cell_padding_x) /
2), y +
(height - fm.getHeight()) / 2 + fm.getAscent());
} else if (value instanceof Integer || value instanceof Long ||
value instanceof Double) {
//居右
g.drawString(value.toString(),
(int) (x +
(width - fm.stringWidth(value.toString()) + width -
fm.stringWidth(value.toString()) - cell_padding_x) /
2), y +
(height - fm.getHeight()) / 2 + fm.getAscent());
} else {
//居中
g.drawString(value.toString(), x + (width - fm.stringWidth(
value.toString())) / 2, y + (height -
fm.getHeight()) / 2 + fm.getAscent());
}
}
}
public static void main(String[] args) {
new SwingCommonPrinitTools().printTable(testData(), "测试");
}
private static TableModel testData() {
final Object rows[][] = {
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", "Test1", "Test2", "Test3"},
{"five", "go - \u4E94", "Test1", "Test2", "Test3"},
{"six", "roku - \u516D", "Test1", "Test2", "Test3"},
{"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"},
{"eight", "hachi - \u516B", "Test1", "Test2", "Test3"},
{"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", "Test1", "Test2", "Test3"},
{"five", "go - \u4E94", "Test1", "Test2", "Test3"},
{"six", "roku - \u516D", "Test1", "Test2", "Test3"},
{"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"},
{"eight", "hachi - \u516B", "Test1", "Test2", "Test3"},
{"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", "Test1", "Test2", "Test3"},
{"five", "go - \u4E94", "Test1", "Test2", "Test3"},
{"six", "roku - \u516D", "Test1", "Test2", "Test3"},
{"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"},
{"eight", "hachi - \u516B", "Test1", "Test2", "Test3"},
{"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", "Test1", "Test2", "Test3"},
{"five", "go - \u4E94", "Test1", "Test2", "Test3"},
{"six", "roku - \u516D", "Test1", "Test2", "Test3"},
{"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"},
{"eight", "hachi - \u516B", "Test1", "Tes12121t2", "Test3"},
{"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", 12, "Test2", "Test3"},
{"five", "go - \u4E94", 121212, "Test2", "Test3"},
{"six", "roku - \u516D", 1212121212, "Test2", "Test3"},
{"seven", "shichi - \u4E03", 12.01, "Test2", "Test3"},
{"eight", "hachi - \u516B", 135.12, "Test2", "Test3"},
{"nine", "kyu - \u4E5D", 93828.34, "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},
{"one", "ichi - \u4E00", "Test1", "Test2", "Test3"},
{"two", "ni - \u4E8C", "Test1", "Test2", "Test3"},
{"three", "san - \u4E09", "Test1", "Test2", "Test3"},
{"four", "shi - \u56DB", "Test1", "Test2", "Test3"},
{"five", "go - \u4E94", "Test1", "Test2", "Test3"},
{"six", "roku - \u516D", "Test1", "Test2", "Test3"},
{"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"},
{"eight", "hachi - \u516B", "Test1", "Test2", "T1212121212est3"},
{"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"},
{"ten", "ju - \u5341", "Test1", "Test2", "Test3"},};
final Object headers[] = {"English", "Japanese", "Column1", "Column2",
"Column3"};
JTable table = new JTable(rows, headers);
return table.getModel();
}
}
前提是保证你的Linux已经安装了相应的Java软件,如果没有安装Java, 先装安装Java,配置Java环境, 假如安装到了/usr/java/jre1.6.0_17/
找到你的FireFox安装的目录,假如安装到了 /usr/firefox
cd /usr/firfox
如果有plugins目录那就继续往下看,如果没有,mkdir plugins
ln -s /usr/java/jre1.6.0_17/plugin/i386/ns7/libjavaplugin_oji.so
OK,至此大功告成,测试一下,打开 http://www.java.com/zh_CN/download/installed.jsp 看看即可
ubuntu下安装这个其实很方便,firefox会自动检测并让你安装,java plugin, 但是在有些Linux环境下就需要手动了。