推荐文章
测试ckeditor代码高亮显示

package jiabin.action;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import jiabin.entity.Notice;
import jiabin.entity.Section;
import jiabin.entity.Topic;
import jiabin.entity.Zone;
import jiabin.service.NoticeService;
import jiabin.service.SectionService;
import jiabin.service.TopicService;
import jiabin.service.ZoneService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**date:2017.04.15
* 功能:由于页面要通过action方法加载从数据库数据,比如帖子列表页面,Topic_list.action
* 而进入首页的时候,要自动加载论坛空间,版块列表,以及帖子数据,而并没有指定的action跳转,所以要初始化指定action来实现加载
* 相应数据
* @author miik
*
*/
@Component
public class InitAction implements ServletContextListener,ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext application=servletContextEvent.getServletContext();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext=applicationContext;
}
}
作者:miki分类:【javaEE】浏览(392)评论(2)
Java 缓存之 Ehcache 详解

一:EhCache是一个纯Java的进程内缓存框架,具有如下特点:
1. 快速简单,非常容易和应用集成。
2.支持多种缓存策略 。
3. 缓存数据有两级:内存和磁盘,因此无需担心容量问题 。
4. 缓存数据会在虚拟机重启的过程中写入磁盘 。
5. 可以通过RMI、可插入API等方式进行分布式缓存。
6. 具有缓存和缓存管理器的侦听接口 。
7. 支持多缓存管理器实例,以及一个实例的多个缓存区域 等特点。
下载地址:
http://sourceforge.net/projects/ehcache/files/
在线文档:
http://tool.oschina.net/apidocs/apidoc?api=ehcache2.5.2
二:cache.xml文件简介
xml文件配置:
ehcache.xml元素的属性:
name:缓存名称
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大
eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
overflowToDisk:true表示当内存缓存的对象数目达到了maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。
diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。
diskPersistent:是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒.
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才
有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态
timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有
效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义.
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
三:Cache的数据淘汰策略
FIFO :first in first out ,这个是大家最熟的,先进先出。
LFU : Less Frequently Used ,一直以来最少被使用的将被清除,缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
LRU (默认):Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,
而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存.
四:缓存数据存储位置:
内存和磁盘;缓存数据会在虚拟机重启的过程中写入磁盘
根据需要将缓存刷到磁盘。将缓存条目刷到磁盘的操作可以通过cache.flush()方法来执行.;
在创建cache的时候,指定了存储在硬盘上也是ok 的,不过没有这个直观。
五:创建Cache的方式以及使用:
A:使用默认配置文件创建:
java代码:
CacheManager manager = CacheManager.create();
B:使用指定配置文件创建:
java代码:
CacheManager manager = CacheManager.create("src/config/ehcache.xml");
C:从classpath中找寻配置文件并创建:
java代码:
URL url = getClass().getResource("/anothername.xml");
CacheManager manager = CacheManager.create(url);
D:通过输入流创建:
java代码:
InputStream fis = new FileInputStream(new File("src/config/ehcache.xml").getAbsolutePath());
try {
manager = CacheManager.create(fis);
} finally {
fis.close();
}
E:卸载CacheManager ,关闭Cache :
java代码:
manager.shutdown();
F:使用Caches :
取得配置文件中预先 定义的sampleCache1设置,通过CacheManager生成一个Cache
java代码:
Cache cache = manager.getCache("demoCache");
G:设置一个名为test 的新cache,test属性为默认:
java代码:
CacheManager manager = CacheManager.create();
manager.addCache("test");
H:设置一个名为test 的新cache,并定义其属性:
java代码:
//CacheManager manager = CacheManager.create();
Cache cache = new Cache("test", 1, true, false, 5, 2);
manager.addCache(cache);
I:往cache中加入元素:
java代码:
Element element = new Element("key1", "value1");
J:从cache中取得元素:
java代码:
Element element = cache.get("key1");
第一步:生成CacheManager对象
第二步:生成Cache对象
第三步:向Cache对象里添加由key,value组成的键值对的Element元素
--------------------- 本文来自 supingemail 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/supingemail/article/details/45365521?utm_source=copy
作者:miki分类:【javaEE】浏览(1277)评论(4)
struts2结合common.fileUpload实现文件带进度条上传

最后,项目还残存的问题就是:明明是每隔500ms向后台请求的进度信息,但是实际上后台并不能够在这段时间内返回对应的信息。亟待优化!
效果图如下:
获取文件上传信息的基本步骤:经测试有效
上传文件时如何获取上传进度信息?
从网上查一下资料就可以知道struts2对文件上传的request请求做了封装,也就是说在调用上传文件的action时就已经上传temp完成了。
那么既然这样,我们就可以重写struts2封装request的类:org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
由于这个类的许多方法都是private的,那么也就是说我们是无法通过extends来重写父类的一些方法的。怎么办呢?
暴力一点!
直接自定义一个JakartaMultiPartRequest类型的类,把父类的方法全部copy过来,然后在struts.xml中配置:
....
接下来我们实现上述配置文件中的MultiPartRequest类:
通过intellij的反编译插件,我们decode JakartaMultiPartRequest这个类:源码如下—-大量代码来袭,直接copy这部分吧 不用细看
/* * $Id: JakartaMultiPartRequest.java 1384107 2012-09-12 20:14:23Z lukaszlenart $ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.struts2.dispatcher.multipart; import com.opensymphony.xwork2.LocaleProvider; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.LocalizedTextUtil; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.RequestContext; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.struts2.StrutsConstants; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; /** * Multipart form data request adapter for Jakarta Commons Fileupload package. */ public class JakartaMultiPartRequest implements MultiPartRequest { static final Logger LOG = LoggerFactory.getLogger(JakartaMultiPartRequest.class); // maps parameter name -> List of FileItem objects protected Map> files = new HashMap>(); // maps parameter name -> List of param values protected Map> params = new HashMap>(); // any errors while processing this request protected List errors = new ArrayList(); protected long maxSize; private Locale defaultLocale = Locale.ENGLISH; @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE) public void setMaxSize(String maxSize) { this.maxSize = Long.parseLong(maxSize); } @Inject public void setLocaleProvider(LocaleProvider provider) { defaultLocale = provider.getLocale(); } /** * Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's * multipart classes (see class description). * * @param saveDir the directory to save off the file * @param request the request containing the multipart * @throws java.io.IOException is thrown if encoding fails. */ public void parse(HttpServletRequest request, String saveDir) throws IOException { try { setLocale(request); processUpload(request, saveDir); } catch (FileUploadBase.SizeLimitExceededException e) { if (LOG.isWarnEnabled()) { LOG.warn("Request exceeded size limit!", e); } String errorMessage = buildErrorMessage(e, new Object[]{e.getPermittedSize(), e.getActualSize()}); if (!errors.contains(errorMessage)) { errors.add(errorMessage); } } catch (Exception e) { if (LOG.isWarnEnabled()) { LOG.warn("Unable to parse request", e); } String errorMessage = buildErrorMessage(e, new Object[]{}); if (!errors.contains(errorMessage)) { errors.add(errorMessage); } } } protected void setLocale(HttpServletRequest request) { if (defaultLocale == null) { defaultLocale = request.getLocale(); } } protected String buildErrorMessage(Throwable e, Object[] args) { String errorKey = "struts.messages.upload.error." + e.getClass().getSimpleName(); if (LOG.isDebugEnabled()) { LOG.debug("Preparing error message for key: [#0]", errorKey); } return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(), args); } private void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException { for (FileItem item : parseRequest(request, saveDir)) { if (LOG.isDebugEnabled()) { LOG.debug("Found item " + item.getFieldName()); } if (item.isFormField()) { processNormalFormField(item, request.getCharacterEncoding()); } else { processFileField(item); } } } private void processFileField(FileItem item) { if (LOG.isDebugEnabled()) { LOG.debug("Item is a file upload"); } // Skip file uploads that don't have a file name - meaning that no file was selected. if (item.getName() == null || item.getName().trim().length() < 1) { LOG.debug("No file has been uploaded for the field: " + item.getFieldName()); return; } List values; if (files.get(item.getFieldName()) != null) { values = files.get(item.getFieldName()); } else { values = new ArrayList(); } values.add(item); files.put(item.getFieldName(), values); } private void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException { if (LOG.isDebugEnabled()) { LOG.debug("Item is a normal form field"); } List values; if (params.get(item.getFieldName()) != null) { values = params.get(item.getFieldName()); } else { values = new ArrayList(); } // note: see http://jira.opensymphony.com/browse/WW-633 // basically, in some cases the charset may be null, so // we're just going to try to "other" method (no idea if this // will work) if (charset != null) { values.add(item.getString(charset)); } else { values.add(item.getString()); } params.put(item.getFieldName(), values); item.delete(); } private List parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { DiskFileItemFactory fac = createDiskFileItemFactory(saveDir); ServletFileUpload upload = new ServletFileUpload(fac); upload.setSizeMax(maxSize); return upload.parseRequest(createRequestContext(servletRequest)); } private DiskFileItemFactory createDiskFileItemFactory(String saveDir) { DiskFileItemFactory fac = new DiskFileItemFactory(); // Make sure that the data is written to file fac.setSizeThreshold(0); if (saveDir != null) { fac.setRepository(new File(saveDir)); } return fac; } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames() */ public Enumeration getFileParameterNames() { return Collections.enumeration(files.keySet()); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String) */ public String[] getContentType(String fieldName) { List items = files.get(fieldName); if (items == null) { return null; } List contentTypes = new ArrayList(items.size()); for (FileItem fileItem : items) { contentTypes.add(fileItem.getContentType()); } return contentTypes.toArray(new String[contentTypes.size()]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String) */ public File[] getFile(String fieldName) { List items = files.get(fieldName); if (items == null) { return null; } List fileList = new ArrayList(items.size()); for (FileItem fileItem : items) { File storeLocation = ((DiskFileItem) fileItem).getStoreLocation(); if (fileItem.isInMemory() &;&; storeLocation != null &;&; !storeLocation.exists()) { try { storeLocation.createNewFile(); } catch (IOException e) { if (LOG.isErrorEnabled()) { LOG.error("Cannot write uploaded empty file to disk: " + storeLocation.getAbsolutePath(), e); } } } fileList.add(storeLocation); } return fileList.toArray(new File[fileList.size()]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String) */ public String[] getFileNames(String fieldName) { List items = files.get(fieldName); if (items == null) { return null; } List fileNames = new ArrayList(items.size()); for (FileItem fileItem : items) { fileNames.add(getCanonicalName(fileItem.getName())); } return fileNames.toArray(new String[fileNames.size()]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String) */ public String[] getFilesystemName(String fieldName) { List items = files.get(fieldName); if (items == null) { return null; } List fileNames = new ArrayList(items.size()); for (FileItem fileItem : items) { fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName()); } return fileNames.toArray(new String[fileNames.size()]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String) */ public String getParameter(String name) { List v = params.get(name); if (v != null &;&; v.size() > 0) { return v.get(0); } return null; } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames() */ public Enumeration getParameterNames() { return Collections.enumeration(params.keySet()); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String) */ public String[] getParameterValues(String name) { List v = params.get(name); if (v != null &;&; v.size() > 0) { return v.toArray(new String[v.size()]); } return null; } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors() */ public List getErrors() { return errors; } /** * Returns the canonical name of the given file. * * @param filename the given file * @return the canonical name of the given file */ private String getCanonicalName(String filename) { int forwardSlash = filename.lastIndexOf("/"); int backwardSlash = filename.lastIndexOf("\\"); if (forwardSlash != -1 &;&; forwardSlash > backwardSlash) { filename = filename.substring(forwardSlash + 1, filename.length()); } else if (backwardSlash != -1 &;&; backwardSlash >= forwardSlash) { filename = filename.substring(backwardSlash + 1, filename.length()); } return filename; } /** * Creates a RequestContext needed by Jakarta Commons Upload. * * @param req the request. * @return a new request context. */ private RequestContext createRequestContext(final HttpServletRequest req) { return new RequestContext() { public String getCharacterEncoding() { return req.getCharacterEncoding(); } public String getContentType() { return req.getContentType(); } public int getContentLength() { return req.getContentLength(); } public InputStream getInputStream() throws IOException { InputStream in = req.getInputStream(); if (in == null) { throw new IOException("Missing content in the request"); } return req.getInputStream(); } }; } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp() */ public void cleanUp() { Set names = files.keySet(); for (String name : names) { List items = files.get(name); for (FileItem item : items) { if (LOG.isDebugEnabled()) { String msg = LocalizedTextUtil.findText(this.getClass(), "struts.messages.removing.file", Locale.ENGLISH, "no.message.found", new Object[]{name, item}); LOG.debug(msg); } if (!item.isInMemory()) { item.delete(); } } } } }
好的,我们把上面这部分代码copy到我们自定义的public class MultiPartRequest extends JakartaMultiPartRequest {}中
复制粘贴完了之后,我们要ctrl f找到parseRequest方法。在这里,我们要设置文件上传进度监听器
/**
* 自定义的parseRequest方法
* @param servletRequest
* @param saveDir
* @return
* @throws FileUploadException
*/
private List parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {
System.out.println("调用parseRequest方法");
UploadProgressListener listener = new UploadProgressListener(servletRequest);
DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setSizeMax(maxSize);
upload.setProgressListener(listener);
System.out.println("设置监听器成功");
return upload.parseRequest(createRequestContext(servletRequest));
}
在上面这个代码片段中可以看到:我们new了一个监听器UploadProgressListener 的实例,然后调用了ServletFileUpload .setProgressListener(listener)方法。也就是说:这里的监听器与我们以前写过的request,session等等监听器不同,不需要在web.xml中配置。这里只需要一行代码即可解决。
那么我们就来实现这个监听器吧!
这个监听器需要实org.apache.commons.fileupload.ProgressListener这个接口:我们直接implement一下。
在update方法中我们可以获取到已上传的文件长度,上传的文件的总长度,当前上传第几个文件。(当你上传一个文件的时候,打印日志就会发现这里会输出2。个人猜测是先上传到temp然后再上传到指定路径…)
我们在update方法中设置了文件上传状态实体类的实例,并且保存到session。这一步就是能让前端使用ajax访问到文件当前的上传进度信息。
package listener; import entity.FileUploadProgress; import org.apache.commons.fileupload.ProgressListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * Created by zipple on 2017/10/13. * 监听文件上传情况 * 实现org.apache.commons.fileupload.ProgressListener接口 */
/**
* 2018.11.27 miki 监听文件上传进度的监听器
*
*/
public class UploadProgress implements ProgressListener {
HttpSession session;
/*
* 实时更新上传进度
* arg0:当前上传文件的大小
* arg1:总共需要上传的大小
* arg2:剩余上传文件的大小
*/
public void update(long arg0, long arg1, int arg2) {
// TODO Auto-generated method stub
if(arg1==0L){
return;
}
//创造json格式参数
String value="var info={read:"+arg0+",total:"+arg1+",items:"+1+"}"; //items:"+arg2+" d多文件上传的时候,使用arg2
// System.out.println(value);
session.setAttribute("progress", value); //上传完毕后,记得清除上传过后的进度条session
}
public UploadProgress(HttpSession session){
this.session=session;
}
}
前端获取后台文件上传的进度信息
上传文件可大致分为两个阶段:1. 上传到服务器上,在临时目录中 2.从临时目录中把文件移到指定目录(由自己写的action处理),而struts2.的监听器只监听
public String upload()throws Exception{
//2017.11.16 21:58 miki 加载网页静态化缓存路径
Properties prop = new Properties();
try {
prop.load(this.getClass().getClassLoader().getResourceAsStream("resource.properties"));
} catch (IOException e1) {
throw new RuntimeException(e1);
}
//2017.11.16 20:37 取静态资源中常量
// String HTML_GEN_PATH = prop.getProperty("HTML_GEN_PATH");//静态资源存储路径
HttpServletResponse response=ServletActionContext.getResponse();
HttpSession session=request.getSession();
user=(User) session.getAttribute("currentUser");
if(user==null){
request.getRequestDispatcher("error.jsp").forward(request, response);
}
System.out.println("上传文件名为:"+uploadFileName);
shop=shopService.getShopByuserId(user.getId());
// 2017.08.05 miki 文件二次命名,作为下载url链接,采用uuid加密命名,并截取2-18位字符,二次加密,增加安全性
String imageName = "file_"+RadomUtil.getUUID().substring(2, 18)+uploadFileName.substring(uploadFileName.lastIndexOf("."));
File newfile = new File(ServletActionContext.getServletContext().getRealPath("/image_upload/source_upload/file")+"\\"+imageName);
IOUtils.cp(upload, newfile); //因为要设置表单里没有的属性(setImage(),)所以重新创造了一个photo对象
//清除上传过后的进度条session
session.setAttribute("progress", null);
source.setPath(imageName);
source.setUser(user);
source.setShop(shop);
source.setUpload_time(new Date());
sourceService.save(source);
user.setScore(user.getScore()+5);
shop.setSourceNum(shop.getSourceNum()+1);
shopService.save(shop);
userService.saveUser(user);
// /*
// * 2017.11.16 20:31 网页静态化实例
// */
// try {
// User vistor=(User) session.getAttribute("currentUser");
// if (StringUtil.isEmpty(page)) {
// page="1";
// }
// PageBean pageBean=new PageBean(Integer.parseInt(page), 6);
// sourceList=sourceService.getSourcesByShopId(shop.getId(), pageBean);
// long total=sourceService.getSourceCountByuserId(shop.getUser().getId());
// StringBuffer param=new StringBuffer();
// param.append("shopId="+shop.getId());
// pageCode=PageUtil.genPagination(request.getContextPath()+"/shop/Shop_view.action", total, Integer.parseInt(page), 6,param.toString());
//
//
// //创建一个数据集,Map将data封装进去
// Map data=new HashMap<>();
// data.put("vistor", vistor);
// data.put("user", user);
// data.put("shop", shop);
// data.put("sourceList", sourceList);
// data.put("pageCode", pageCode);
// //加载模板对象
// Configuration configuration=freeMarkerConfigurer.getConfiguration();
// Template template = configuration.getTemplate("shop.ftl");
// //创建一个输出流,指定目录及文件名
// Writer out=new FileWriter(HTML_GEN_PATH +shop.getId()+ ".html");
// //生成静态页面
// template.process(data, out);
// //关闭流
// out.close();
//
// } catch (Exception e) {
// // TODO: handle exception
// e.printStackTrace();
// }
return "su";
}
返回json数据的struts.xml配置如下:
shop/Shop_upload.action
项目做到这里,后端的事情已经做完了。接下来就是前端显示进度条的事情。需要的同学可以继续往下看咯。
前端那些事儿——css实现进度条控件
css:可以直接copy,无需细看(firefox下测试无问题)
控制进度条代码:在提交文件时同步调用此计时器即可。
...
if('${shop.sourceNum}'=='${shop.maxNum}'){
$("#error").html("*您已达到资源上传上限,请升级权限再来*");
return false;
}
$("#error").html("");
createProgress();
//getProgress(); //定时刷新
setTimeout("getProgressBar()",1000);
return true;
/** * 展示上传进度条 */
作者:miki分类:【javaEE】浏览(1303)评论(3)
# 宇加业务协同平台-Mxgraph常用方法

# 宇加业务协同平台-Mxgraph常用方法
###仅供参考,不对的地方或者有更好的方法可以修正
##判断浏览器兼容性
```
if (!mxClient.isBrowserSupported()) {
// Displays an error message if the browser is not supported.
mxUtils.error('您当前浏览器不支持此组件!', 200, false);
}else {
....正文
}
```
##常用的全局属性配置[graph.setXXXX(bool)]
```
// j禁用浏览器右键菜单
mxEvent.disableContextMenu(container);
//添加框选
new mxRubberband(graph);
//细胞可以克隆
graph.setCellsCloneable(true);
//是否允许线悬吊着,摆动不定
graph.setAllowDanglingEdges(false);
//禁止放大缩小
graph.setCellsResizable(false);
//禁用折叠
graph.foldingEnabled = false;
// 启用工具提示、新连接和平移
graph.setPanning(true);
// 开启鼠标悬停提示
graph.setTooltips(true);
//设置可连接性
graph.setConnectable(true);
graph.setMultigraph(false);
//去锯齿效果
mxRectangleShape.prototype.crisp = true;
// 是否启用对齐线帮助定位
mxGraphHandler.prototype.guidesEnabled = true;
//定义对齐线颜色
mxConstants.GUIDE_COLOR = "#00A3D9";
// 是否缩放网格
// mxGraphHandler.prototype.scaleGrid = true;
// 是否开启旋转
mxGraphHandler.prototype.rotationEnabled = false;
// 选择基本元素开启
graph.setEnabled(true);
// 开启文字编辑功能
graph.setCellsEditable(true);
//开启回车退出编辑
graph.setEnterStopsCellEditing(true);
// 鼠标悬浮在节点上显示浮动框
new mxCellTracker(graph, '#8BF19F');
```
##常用方法
```
//根据ID获取cell
graph.getModel().getCell(uuid)
```
##属性重定义方法[graph.isXXX(function(cell){})]
```
//根据ID获取cell
graph.getModel().getCell(uuid)
```
##属性重定义方法[graph.isXXX(function(cell){})]
```
// 重定义哪些cell锁定
graph.isCellLocked = function(cell) { //锁定连线,不可随意拖动
// if (graph.getModel().isEdge(cell)) {
// return true;
// }else{
return false;
//}
};
//重定义哪些cell可以移动
graph.isCellMovable = function(cell) {
if(cell.type && cell.type == "taskType") {
return false;
} else {
return true;
}
};
//获取当前选中的cell
var cell = graph.getSelectionCell();
if (cell == null) {
// Ext.Msg.alert('没有选择图形元素'); //'没有选择图形元素!'
return;
}
var objId = cell.getId(); //元素ID
var enc = new mxCodec();
var node = enc.encode(cell); //解析为DOM对象时自定义属性才可以识别
var nodetype = node.getAttribute('nodetype'); //取节点类型,如果是线则为空
var source = node.getAttribute('source'); //取线的来源节点ID,如果是节点则值为空
// var config = mxUtils.getXml(node);
// 新窗口打开
mxUtils.popup(mxUtils.getXml(node));
// }
```
## 添加监听事件的方法
```
graph.addMouseListener(mxEvent.MOUSE_DOWN,function () {
alert(1111);
});
//设置节点的鼠标移入手型移出鼠标指示效果
var track = new mxCellTracker(graph);
track.mouseMove = function (sender, me) {
var cell = this.getCell(me);
if (cell) {
//设置鼠标为样式为手状
me.getState().setCursor('pointer');
// updateStyle(cell, true);
} else {
// updateStyle(cell, false);
}
};
//最常用的监听点击事件的
graph.addListener(mxEvent.CLICK, function (sender, evt) {
var cell = evt.getProperty('cell');
if (!cell) return false;
console.log('我点击了节点哦!');
console.log(cell);
var enc = new mxCodec();
var node = enc.encode(cell);
console.log(node);
});
//监听鼠标按下,移动,抬起事件
graph.addMouseListener({
mouseDown: function (sender, me) {
console.log('mouseDown');
},
mouseMove: function (sender, me) {
// console.log('mouseMove');
},
mouseUp: function (sender, me) {
console.log('mouseUp');
},
dragEnter: function (evt, state) {
console.log('dragEnter');
// if (state != null) {
// this.previousStyle = state.style;
// state.style = mxUtils.clone(state.style);
// updateStyle(state, true);
// state.shape.apply(state);
// state.shape.redraw();
//
// if (state.text != null) {
// state.text.apply(state);
// state.text.redraw();
// }
// }
},
dragLeave: function (evt, state) {
console.log('dragLeave');
// if (state != null) {
// state.style = this.previousStyle;
// updateStyle(state, false);
// state.shape.apply(state);
// state.shape.redraw();
//
// if (state.text != null) {
// state.text.apply(state);
// state.text.redraw();
// }
// }
},
dragover: function (evt, state) {
console.log('dragover');
},
drop: function (evt, state) {
console.log('drop');
}
});
graph.addListener({
dragover: function (evt, state) {
console.log('dragover');
},
drop: function (evt, state) {
console.log('drop');
}
});
mxEvent.addListener(container, 'dragover', function (evt) {
if (graph.isEnabled()) {
evt.stopPropagation();
evt.preventDefault();
}
});
mxEvent.addListener(container, 'drop', function (evt) {
if (graph.isEnabled()) {
evt.stopPropagation();
evt.preventDefault();
// Gets drop location point for vertex
var pt = mxUtils.convertPoint(graph.container, mxEvent.getClientX(evt), mxEvent.getClientY(evt));
var tr = graph.view.translate;
var scale = graph.view.scale;
var x = pt.x / scale - tr.x;
var y = pt.y / scale - tr.y;
console.log(x);
console.log(y);
console.log(event);
// Converts local images to data urls
var filesArray = event.dataTransfer.files;
console.log(filesArray);
// for (var i = 0; i < filesArray.length; i++) {
// handleDrop(graph, filesArray[i], x + i * 10, y + i * 10);
// }
}
});
```
## 定义默认样式以及样式类
```
//默认VertexStyle
var style = new Object();
style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;
style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
style[mxConstants.STYLE_FONTCOLOR] = '#000000';
style[mxConstants.STYLE_FONTSIZE] = '11';
style[mxConstants.STYLE_FONTSTYLE] = 0;
graph.getStylesheet().putDefaultVertexStyle(style);
var style = new Object();
style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
style[mxConstants.STYLE_OPACITY] = 50;
style[mxConstants.STYLE_FONTCOLOR] = '#774400';
graph.getStylesheet().putCellStyle('ROUNDED', style);
//标准子过程样式
style = new Object();
style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; //形状
style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; //垂直对齐
style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP; //水平对齐
style[mxConstants.STYLE_GRADIENTCOLOR] = '#DEE6E8'; //渐变色
style[mxConstants.STYLE_FILLCOLOR] = '#FAFAFA'; //填充色
style[mxConstants.STYLE_SWIMLANE_FILLCOLOR] = '#ffffff'; //swimlane填充色
style[mxConstants.STYLE_STROKECOLOR] = '#9DA5A7'; //表头边框颜色
style[mxConstants.STYLE_FONTCOLOR] = '#000000'; //字体颜色
style[mxConstants.STYLE_STROKEWIDTH] = '1'; //边框粗细
style[mxConstants.STYLE_STARTSIZE] = '28'; //表头部高度
style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle';
style[mxConstants.STYLE_FONTSIZE] = '12'; //字体大小
style[mxConstants.STYLE_FONTSTYLE] = 1;
graph.getStylesheet().putCellStyle('standrad_tabStyle', style);
//本节点
thisPointStyle = mxUtils.clone(style);
thisPointStyle["image"] = 'resources/images/graph/thisPoint.png';
thisPointStyle["fontSize"] = '16';
thisPointStyle["fontColor"] = '#fff';
thisPointStyle['constituent'] = "1";
thisPointStyle["verticalLabelPosition"] = "middle";
thisPointStyle["verticalAlign"] = "middle";
thisPointStyle["spacingTop"] = "4";
thisPointStyle["align"] = "center";
graph.getStylesheet().putCellStyle("thisPointStyle", thisPointStyle);
//节点状态
statusPointStyle = mxUtils.clone(style);
statusPointStyle['constituent'] = "1";
statusPointStyle["image"] = 'resources/images/graph/status-normal.png';
graph.getStylesheet().putCellStyle("statusPointStyle", statusPointStyle);
//添加数据节点
addDataPointStyle = mxUtils.clone(style);
addDataPointStyle["image"] = 'resources/images/graph/addDataPoint.png';
addDataPointStyle["imageWidth"] = '64';
addDataPointStyle["imageHeight"] = '64';
addDataPointStyle["fontColor"] = '#00A3D9';
//默认线条样式
edgeStyle = graph.getStylesheet().getDefaultEdgeStyle();
edgeStyle["rounded"] = true;
edgeStyle["shape"] = "connector";
edgeStyle["strokeWidth"] = 1;
edgeStyle["strokeColor"] = "#2C9C39";
MQEdgeStyle = mxUtils.clone(edgeStyle);
MQEdgeStyle["edgeStyle"] = 'elbowEdgeStyle';
MQEdgeStyle["startArrow"] = 'oval';
//MQEdgeStyle["endArrow"] = 'block';
MQEdgeStyle["endArrow"] = 'oval';
MQEdgeStyle["startFill"] = 0;
MQEdgeStyle["endFill"] = 0;
MQEdgeStyle["entryX"] = 0;
MQEdgeStyle["entryY"] = 0.5;
MQEdgeStyle["exitX"] = 1;
MQEdgeStyle["exitY"] = 0.5;
graph.getStylesheet().putCellStyle("MQEdgeStyle", MQEdgeStyle);
```
## 画图
```
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
//Adds cells to the model in a single step
graph.getModel().beginUpdate();
try {
var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
var e1 = graph.insertEdge(parent, null, '', v1, v2);
//画方块 默认情况下
graph.insertVertex(parent, null, '矩形', 50, 50, 150, 150);
// 画方块 圆角矩形
shape=rounded 定义圆角 arcSize=10 定义圆角弧度
graph.insertVertex(parent, null, '圆角矩形', 300, 50, 150, 150, "rounded=true;perimeter=ellipsePerimeter;arcSize=20;");
//画椭圆
shape=elipse 定义椭圆 perimeter=ellipsePerimeter 让连线的箭头或起点触到边缘
graph.insertVertex(parent, null, '椭圆', 550, 50, 150, 150, "shape=ellipse;perimeter=ellipsePerimeter;");
//画三角形
shape=triangl 定义三角形 perimeter=ellipsePerimeter 让连线的箭头或起点触到边缘 direction=south 让三角形倒立
graph.insertVertex(parent, null, '三角形', 800, 50, 150, 150, "shape=triangle;perimeter=ellipsePerimeter;direction=south;");
//画菱形
shape=rhombus 定义菱形
graph.insertVertex(parent, null, '三角形', 1050, 50, 150, 150, "shape=rhombus;perimeter=ellipsePerimeter;");
//画柱形
shape=cylinder 定义柱形
graph.insertVertex(parent, null, '柱形', 1300, 50, 150, 150, "shape=cylinder;perimeter=ellipsePerimeter;");
//画人
shape=actor 定义演员
graph.insertVertex(parent, null, '演员', 50, 300, 150, 150, "shape=actor;perimeter=ellipsePerimeter;");
//画云
graph.insertVertex(parent, null, '云', 300, 300, 150, 150, "shape=cloud;perimeter=ellipsePerimeter;");
// 矩形默认情况下
graph.insertVertex(parent, null, '矩形', 550, 300, 150, 150, "shape=rectangle;perimeter=ellipsePerimeter;");
// 泳道
graph.insertVertex(parent, null, '泳道', 800, 300, 150, 150, "shape=swimlane;perimeter=ellipsePerimeter;");
// 双圆
graph.insertVertex(parent, null, '双圆', 1050, 300, 150, 150, "shape=doubleEllipse;perimeter=ellipsePerimeter;");
// 六边形
graph.insertVertex(parent, null, '六边形', 1300, 300, 150, 150, "shape=hexagon;perimeter=ellipsePerimeter;");
}finally {
// Updates the display
graph.getModel().endUpdate();
}
```
## 导出XML
```
//转XML格式输出
var encoder = new mxCodec();
var node = encoder.encode(graph.getModel());
console.log(mxUtils.getXml(node));
扩充版(解决浏览器兼容问题)
//获取当前编辑指标的名称、xml
getGraphXML : function() {
//生成graph视图的xml格式文件
var getGraphXml = function(graph) {
var encoder = new mxCodec();
var code = encoder.encode(graph);
return code;
}
var model = graph.getModel();
if (model) {
var graphXmlObj = getGraphXml(model);
if (judgeIsIe8()) {
//console.log("ie8");
graphXmlForIe = graphXmlObj.xml; //<>转义得用第三变量传递一下,不能用var graphXml
return graphXmlForIe;
} else {
var oSerializer = new XMLSerializer();
var report_xmlStr = oSerializer.serializeToString(graphXmlObj);
graphXmlOther = report_xmlStr;
return graphXmlOther;
}
}
}
```
## 回显XML
```
// XML回显到编辑区(渲染画布)
var xmlFile = '<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="Hello," vertex="1" parent="1"><mxGeometry x="20" y="20" width="80" height="30" as="geometry"/></mxCell><mxCell id="3" value="World!" vertex="1" parent="1"><mxGeometry x="200" y="150" width="80" height="30" as="geometry"/></mxCell><mxCell id="4" value="" edge="1" parent="1" source="2" target="3"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="5" value="矩形" vertex="1" parent="1"><mxGeometry x="50" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="6" value="圆角矩形" style="rounded=true;perimeter=ellipsePerimeter;arcSize=20;" vertex="1" parent="1"><mxGeometry x="300" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="7" value="椭圆" style="shape=ellipse;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="550" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="8" value="三角形" style="shape=triangle;perimeter=ellipsePerimeter;direction=south;" vertex="1" parent="1"><mxGeometry x="800" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="9" value="三角形" style="shape=rhombus;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="1050" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="10" value="柱形" style="shape=cylinder;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="1300" y="50" width="150" height="150" as="geometry"/></mxCell><mxCell id="11" value="演员" style="shape=actor;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="50" y="300" width="150" height="150" as="geometry"/></mxCell><mxCell id="12" value="云" style="shape=cloud;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="300" y="300" width="150" height="150" as="geometry"/></mxCell><mxCell id="13" value="矩形" style="shape=rectangle;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="550" y="300" width="150" height="150" as="geometry"/></mxCell><mxCell id="14" value="泳道" style="shape=swimlane;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="800" y="300" width="150" height="150" as="geometry"/></mxCell><mxCell id="15" value="双圆" style="shape=doubleEllipse;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="1050" y="300" width="150" height="150" as="geometry"/></mxCell><mxCell id="16" value="六边形" style="shape=hexagon;perimeter=ellipsePerimeter;" vertex="1" parent="1"><mxGeometry x="1300" y="300" width="150" height="150" as="geometry"/></mxCell></root></mxGraphModel>';
var doc = mxUtils.parseXml(xmlFile),
dec = new mxCodec(doc);
dec.decode(doc.documentElement, graph.getModel());
扩充版(解决浏览器兼容问题)
//解析xml字符串并转化成graph视图
createXmlDom : function(str) {
if (document.all) { //判断浏览器是否是IE
var xmlDom = new ActiveXObject("Microsoft.XMLDOM");
xmlDom.loadXML(str);
return xmlDom;
} else {
return (new DOMParser()).parseFromString(str, "text/xml");
}
},
readGraphXML : function(xmlstr, graph) {
if (xmlstr) {
graph.getModel().beginUpdate();
try {
var xmlDoc = this.createXmlDom(xmlstr);
var node = xmlDoc.documentElement;
var dec = new mxCodec(node.ownerDocument);
dec.decode(node, graph.getModel());
console.log(dec);
} finally {
graph.getModel().endUpdate();
}
}
}
```
##右键菜单
```
graph.popupMenuHandler.autoExpand = true;
graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {
if(cell != null) {
menu.addItem('添加节点', null, function() {
changeTaskType(cell.id, "")
});
//二级菜单
var conn_pos = menu.addItem('连接位置', null, function() {});
menu.addItem('左右', null, function() {}, conn_pos);
menu.addItem('三面', null, function() {}, conn_pos);
menu.addItem('四面', null, function() {}, conn_pos);
menu.addItem('设置', null, function() {});
menu.addItem('详细信息', null, function() {});
menu.addItem('远程更新版本', null, function() {});
menu.addItem('远程控制(新窗口)', null, function() {
window.open('index.html?serverUUID=' + cell.id + '&serverName=' + encodeURI(cell.value));
});
menu.addItem('查看目录', null, function() {
viewDataDirectoryWin.show(data.UUID, data.subOrSup);
});
menu.addItem('查看话题', null, function() {
viewTopicWin.show(data.UUID, data.subOrSup);
});
}
}
```
## 组合型shape配置
```
// Helper method to mark parts with constituent=1 in the style
//在style里面用constituent=1标记部件
graph.isPart = function(cell) {
var state = this.view.getState(cell);
var style = (state != null) ? state.style : this.getCellStyle(cell);
return style['constituent'] == '1';
};
// 重定义组合型图形的选中事件,不能选中里面的子部件
graph.selectCellForEvent = function(cell) {
if(this.isPart(cell)) {
cell = this.model.getParent(cell);
}
mxGraph.prototype.selectCellForEvent.apply(this, arguments);
};
```
## 绘制组合图形
```$xslt
var parent = graph.getDefaultParent();
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try {
var taskWrap = graph.insertVertex(parent, "Taskid", 'Looped\nSub-Process', 200, 200, 200, 100, 'whiteSpace=wrap;');
//constituent=1;表示节点作为一个part存在的
var taskTypeCell = graph.insertVertex(taskWrap, null, 'dfdfgd', 0.5, 1, 30, 30, 'shape=ellipse;fontSize=9;constituent=1;resizable=0;;outlineConnect=0;');
taskTypeCell.type = "taskType";
taskTypeCell.expr = "ffffffffffffffffff";
taskTypeCell.geometry.relative = true;
taskTypeCell.geometry.offset = new mxPoint(-15, -35);
taskTypeCell.connectable = false;
taskTypeCell.value = "jshdjhsdbvf";
} finally {
// Updates the display
graph.getModel().endUpdate();
}
```
##边缘事件
```
参考/examples/boundary.html
```
## 设置style样式[graph.setCellStyles(mxConstant.xxxx,设置的val, [cells])]
```
var changeTaskType = function(cellId, Task) {
var endFill = "";
var graph = myGraphInfo.graph;
switch(examine) {
case "EXAMINE_ADOPT": //审批通过
endFill = 1;
break;
case "EXAMINE_REJECT": //审批拒绝 case :
case "EXAMINE_CONNECT":
case "EXAMINE_NOT": //未审批 case :
case "EXAMINING": //待审批
endFill = 0;
break;
}
var thisCell = graph.getModel().getCell(uuid);
var thisEdge = thisCell.edges[0];
graph.setCellStyles("shape", "", [cell]);
graph.refresh(thisEdge);//刷新改细胞
}
```
##限制最大最小宽度
```aidl
graph.cellResized = function (cell, rect, ignoreRelative, recurse) {
var flagClass = "mxCol_" + cell.id;
if (rect.width < 40) {
rect.width = 40;
$("." + flagClass).width("0px");
} else if (rect.width > 800) {
rect.width = 800;
$("." + flagClass).width((800 - 43) + "px");
} else {
$("." + flagClass).width((rect.width - 43) + "px");
}
return mxGraph.prototype.cellResized.apply(this, arguments);
};
```
##关于是否可连接设置
```aidl
//目标可连接性设置
graph.isValidTarget = function (cell) {
if (cell) {
if (cell.type) {
if (cell.type == "table" || cell.type == "gather") {
// designMxgraph.setTabConnectable(true);
return true;
}
}
}
}
//连线可行性验证
graph.validateEdge = function (edge, source, target) {
if (!edge) {
// designMxgraph.setTabConnectable(false);
} else {
return true;
}
}
```
##Drop拖动目标验证
```aidl
//Drop拖动目标验证
//cell:target
//cells:source 一般用于group
graph.isValidDropTarget = function (cell, cells, evt) {
if (cell) {
if (cells.length == 1) {
source = cells[0];
if (cell.type == "group" && cells[0].type != "group" && cells[0].type != "gather") {
if (source.edges) {
for (var i = 0; i < source.edges.length; i++) {
if (source.edges[i].id.indexOf("flowline_") != -1) {//针对流向线
if (source.edges[i].target.id != source.id) {
return false;//一旦线的目标终点不是source本身,就不可以拖进去
} else if (source.edges[i].source.id == cell.id) {
return false;
} else {
continue;
}
}
}
}
return true;
}
}
}
}
```
##获取所有画布内得图形对象
```aidl
graph.getChildCells()---包括连线
graph.getChildVertices()---不包括连线
```
##设置细胞可连接性
```aidl
cell.setConnectable(bool);
```
##泳道布局
```aidl
//配置泳道里的细胞自动布局,泳道布局
editor.layoutSwimlanes = true;
editor.createSwimlaneLayout = function () {
var layout = new mxStackLayout(this.graph, false);
layout.fill = true;
layout.resizeParent = true;
// Overrides the function to always return true
layout.isVertexMovable = function (cell) {
return true;
};
return layout;
};
```
##添加A细胞到B细胞的连线
```aidl
var newLine = graph.insertEdge(parent, id, label, startCell, endCell, 'dashed=1;' +
'startArrow=oval;endArrow=oval;sourcePerimeterSpacing=4;startFill=1;endFill=1;strokeColor=green;' +
'strokeWidth=1;fontSize=12;edgeStyle=sideToSideEdgeStyle;');
dashed----
startArrow----线头起始形状 有oval(圆形),classic(箭头),none(无)
endArrow-----线头结束形状
startFill、endFill-----是否填充颜色
edgeStyle----线条的类型
entryX,entryY---结尾的落点坐标
exitX,exitY----开始的坐标
sourcePerimeterSpacing---留白
```
clickhouse,mysql,oracle查询表指定记录数量

1. 那么Oracle中有limit吗,答案是没有。oracle中可以通过 rownumber
Oracle使用rownum的关键字来实现这种查询,首先我们假设有一个地域信息表area123,其表结构如下图所示:
2.mysql的imit方法:
MYSQL 中 LIMIT 用法
mapper文件中的sql:
--------------------------------------------------------------------------------------------
(在实体类中定义的属性)
start:从第几条记录开始。
size:读取几条记录。
select id="findAllUsers" parameterType="Map" resultType="entity.IUser">
select * from newusers
<where>
user_name like #{user_name,jdbcType=VARCHAR}
</where>
limit #{start,jdbcType=INTEGER},#{size,jdbcType=INTEGER}
</select>
------------------------------------------------------------------
前端将page:第几页
rows(size):每页多少条
这两个参数,传到后台。
通过这两个参数,可以算出start 计算方法 start=size(page-1)
然后将size和start放入map中
简单代码示例
Map map=new HashMap();
map.put("start",start);
map.put("size",size);
不要忘记将start和size转换成Integer.
然后将map当作参数传入dao的接口。
注:
limit是mysql的语法
select * from table limit m,n
其中m是指记录开始的index,从0开始,表示第一条记录
n是指从第m+1条开始,取n条。
select * from tablename limit 2,4
即取出第3条至第6条,4条记录
3. clickhouse 使用limit方法
具体用法如下:
关于社区未来规划及发展
现在进入整体布局第二期,工程整体布局已经完成大半,现在欠缺的就是两部分,一个是对全部博客做一个归类的首页,
类似于csdn社区系统,另一个则是对博客系统的后台管理,整体联系有点乱。
1.关于系统的bug,如果刚导入数据的时候,有些类型为null,则无法查到数据。null和“”
的区别相信大家都略知其一了。
2.关于ajax的使用,这个东西可以说是难为了我好久,有句话形容我的心情再好不过了,如同鸡肋 ,食之无味,弃之可惜。
我不希望每次都刷新全局,异步提交。但是学不会。这个暑假我要认真学习一下
3.项目无关性虽然不错,客户体验也还说的过去,但是管理员对整体的掌控和把握欠缺太多,这个很致命
4.留给我的时间不多了,所以我希望可以把它完善的尽善尽美。接下来,我还要再做一个管理系统,
和一个商城项目。然后学习一下,ajax和数据库管理。
5.还有maven以及springMVC这两个框架。
代码高亮测试第三单

String from=props.getProperty("from");
String title=props.getProperty("subject");
String to = Tuser.getEmail();
String content = MessageFormat.format(props.getProperty("content"), topic.getId(),topic.getTitle()); //内容
message.setFrom(new InternetAddress(from));
message.setRecipients(Message.RecipientType.TO,to);
//邮件标题
message.setSubject(title);
//文本部分
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent("<img src='cid:myimg'/><div style='width:1193px; height:100px;border:1px solid red'>"+content+"</div>", "text/html;charset=UTF-8");
//内嵌图片部分
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.setDataHandler(new DataHandler(new FileDataSource("D:/soft/logo.jpg")));//图片路径
imagePart.setContentID("myimg");
//图文整合,关联关系
MimeMultipart mmp1 = new MimeMultipart();
mmp1.addBodyPart(textPart);
mmp1.addBodyPart(imagePart);
mmp1.setSubType("related");
MimeBodyPart textImagePart = new MimeBodyPart();
textImagePart.setContent(mmp1);
//附件部分
MimeBodyPart attachmentPart = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("D:/soft/freemarker/file/sharehoo社区福利.txt"));//文件路径
String fileName = dh.getName();
attachmentPart.setDataHandler(dh);
attachmentPart.setFileName(fileName);
//图文和附件整合,复杂关系
MimeMultipart mmp2 = new MimeMultipart();
mmp2.addBodyPart(textImagePart);
mmp2.addBodyPart(attachmentPart);
mmp2.setSubType("mixed");
//将以上内容添加到邮件的内容中并确认
message.setContent(mmp2);
message.saveChanges();
//发送邮件
Transport.send(message);
关于社区论坛版块的置顶,精华,撤销功能说明

1.对于已置顶的帖子设置两个操作:撤销,精华
之所以这样设置的原因,是撤销功能将帖子的精华和置顶全部设为0,这样的话,帖子就会被降级,降级之后可以执行删除操作或者置顶操作。但是对置顶帖不能执行删除操作。只有将其降级之后,才能实现删除功能
2.同理,对于普通帖的列表操作选项,有置顶和删除操作,帖子的优先筛选条件是通过访问量多少对其采取置顶操作,访问量,回复量多的可以置顶,置顶之后,如果是优质帖子,可以对其采取精华操作。当然,普通帖才有删除的操作,这就是权限的不同。
3.附图看一看,啥啊也不说了,一言不合就上图:
a 标签中调用js函数的几种方法介绍及分析

我们常用的在a标签中有点击事件:
1. a href="JavaScript:js_method();"
这是我们平台上常用的方法,但是这种方法在传递this等参数的时候很容易出问题,而且javascript:协议作为a的href属性的时候不仅会导致不必要的触发window.onbeforeunload事件,在IE里面更会使gif动画图片停止播放。W3C标准不推荐在href里面执行javascript语句
2. a href="javascript:void(0);" onclick="js_method()"
这种方法是很多网站最常用的方法,也是最周全的方法,onclick方法负责执行js函数,而void是一个操作符,void(0)返回undefined,地址不发生跳转。而且这种方法不会像第一种方法一样直接将js方法暴露在浏览器的状态栏。
3.a href="javascript:;" onclick="js_method()"
这种方法跟跟2种类似,区别只是执行了一条空的js代码。
4.a href="#" onclick="js_method()"
这种方法也是网上很常见的代码,#是标签内置的一个方法,代表top的作用。所以用这种方法点击后网页后返回到页面的最顶端。
5.a href="#" onclick="js_method();return false;"
这种方法点击执行了js函数后return false,页面不发生跳转,执行后还是在页面的当前位置。
我看了下taobao的主页,他们采用的是第2种方法,而alibaba的主页是采用的第1种方法,和我们的区别是每个href里的javascript方法都用try、catch包围。
综合上述,在a中调用js函数最适当的方法推荐使用:
a href="javascript:void(0);" onclick="js_method()"
a href="javascript:;" onclick="js_method()"
a href="#" onclick="js_method();return false;"
js的方法中 字符串型要加引号