2019-06-12

Spring不使用数据库查询分页

```java
List content = your result set;
Pageable pageable= new PageRequest(int page, int size);
long total = cound found elements;
PageImpl pager = new PageImpl(content,pageable,cound );
```

Java Runtime.exec取stderr阻塞

原因:


Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
翻译:
一些平台只为标准输入输出提供有限的缓存。错误的写子进程的输入流或者错误的都子进程的输出流都有可能造成子进程的阻塞,甚至是死锁。

解决方法:

把读取stderr及stdout的操用放到单独的线程中,示例代码:

```java
Process process = Runtime.getRuntime().exec(this.command, envs);
 //System.out.println("-------------------------------------");
 BufferedReader ebr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
 Thread eThread = new Thread(() -> 
 try 
 String eline;
 while (null != (eline = ebr.readLine())) 
 System.out.println("[Error]" + eline);
 
 ebr.close();
 catch (Exception e) 
 e.printStackTrace();
 
 );
 eThread.start();
 //System.out.println("-------------------------------------");
 BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
 Thread oThread = new Thread(() -> 
 try 
 String line;
 while (null != (line = br.readLine())) 
 System.out.println(line);
 
 br.close();
 br.close();
 catch (Exception e) 
 e.printStackTrace();
 
 );
 oThread.start();
 process.waitFor();
 ```
 

[WEB前端]纯Javascript全选checkbox

```javascript
var cbs = document.querySelectorAll('input[type="checkbox"]');
for(var i=0; i < cbs.length; i++){
 cbs[i].checked = true;
}
```

Spring-Boot随文件系统动态载入静态资源

在application.properties中加入file:/类型静态目录定义,不要忘记了classpath下的static


spring.resources.static-locations=classpath:/static/,file:/opt/tools/html/

在启动jar时,使用

--spring.config.location=application.properties
路径来使用自定义配置

Java Swing带进度条的splash

编程原理:

取得SplashScreen的实例后,在该实例下创建2D画图对象,根据x, y坐标手动绘制文字及进度条,每绘制一次,调用一次SplashScreen.update进行splash的更新

前提条件:

必须使用java的-splash:splash.png参数设定好要用的splash图片

示例代码:

[code lang="java"]
public static void main(String args[])
SplashScreen splash = SplashScreen.getSplashScreen();
try
if (splash == null)
System.out.println("No splash image...");
else
Graphics2D g2 = splash.createGraphics();
Rectangle bounds = splash.getBounds();
int progressY = (int) bounds.getHeight() - 24;
int progressW = (int) bounds.getWidth() - 8;
//g2.setColor(Color.BLACK);
g2.fillRect(4, progressY, progressW, 20);

g2.setColor(Color.BLACK);
g2.drawString("初始化对象......", 4, progressY - 12);
g2.setColor(Color.BLUE);
int curW = (int) (progressW * 0.3);
g2.fillRect(4, progressY, curW, 20);
Thread.sleep(90);
splash.update();
Nmcli gui = Nmcli.getInstance();
g2.setColor(Color.BLACK);
g2.drawString("初始化窗口......", 4, progressY - 12);
g2.setColor(Color.BLUE);
curW = (int) (progressW * 0.6);
g2.fillRect(4, progressY, curW, 20);
Thread.sleep(90);
splash.update();
gui.initGUI();
g2.setColor(Color.BLUE);
g2.fillRect(4, progressY, progressW, 20);
gui.show();

catch (Exception e)
e.printStackTrace();

Spring boot with file upload

首先需配置一个Multipart File Resolver,只需在配置类中加入一个返回CommonsMultipartResolver对象Bean的multipartResolver方法:





@Configuration





publicclassImageUploaderConfig





@Bean





publicCommonsMultipartResolvermultipartResolver()





CommonsMultipartResolverresolver=newCommonsMultipartResolver();





resolver.setMaxUploadSize(1000000);





returnresolver;













在Controller中使用Apache commons.io来简化io操作





@PostMapping("/ImageUploaderAction")





@ModelAttribute





publicStringimageUploaderAction(Modelmodel,MultipartFilefile)





Stringinfo="TestDemo";





if(file==null)





info="Youmustselectaimagefile";





else





if(!file.getOriginalFilename().endsWith(".jpeg")&&





!file.getOriginalFilename().endsWith(".jpg")&&





!file.getOriginalFilename().endsWith("png"))





info="OnlysupportJPEG/PNGfiles";





else





try





FileUtils.writeByteArrayToFile(newFile(this.storagePath+file.getOriginalFilename()),





file.getBytes());





info="Uploadsuccessfully,yourimageURLis:["+this.baseUrl+file.getOriginalFilename()+"]";









catch(IOExceptione)





e.printStackTrace();





info="Failtouploadimage,checkyourfile";

















model.addAttribute("info",info);





return"ImageUploaderAction";









View中的form记得加入enctype="multipart/form-data"

Spring boot with web security

正确开启Web Security的方法:





定义WEB用户数据表Entity结构类(Model),





定义对应的JPA接口JPARepository,





定义对应的实现了UserDetailsService的用户详情类





@EnableWebSecurity写在Application类前面





定义一个带@Configuration,且基于WebSecurityConfigurerAdapter的配置类,重写两个configure方法,分别定义authentication(认证)和authorization(授权)行为





authentication设置





http.authorizeRequests()





.antMatchers("/error","/favicon.ico",
"/data/**", "/js/**", "/dist/**",
"/vendor/**").permitAll()





.anyRequest().authenticated()





.and().formLogin().loginPage("/login")





.failureUrl("/login?error").defaultSuccessUrl("/home").permitAll().and().logout().permitAll();





authorization设置





auth.userDetailsService(customUserService()).passwordEncoder(NoOpPasswordEncoder.getInstance());





注意点:





/error 需加入至permitAll中,否则错误页面会302





由于spring
security默认开启csrf,需在表单中加入以下csrf字段:





<input
type="hidden" th:name="$_csrf.parameterName"
th:value="$_csrf.token">





Spring security默认的权限查询SQL,用户及权限表字段设计需有下面的必需字段:





DEF_AUTHORITIES_BY_USERNAME_QUERY        "select
username,authority from authorities where username = ?"





DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY        "select
g.id, g.group_name, ga.authority from groups g, group_members gm,
group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id =
gm.group_id"





DEF_USERS_BY_USERNAME_QUERY        "select
username,password,enabled from users where username = ?"





登陆表单,用户名:username,密码:password





AuthenticationManagerBuilder密码编码配置:





推荐的BCrypt算法:





auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());





PLAINTEXT,明文,不推荐:





auth.userDetailsService(customUserService()).passwordEncoder(NoOpPasswordEncoder.getInstance());

Spring Boot with Maven

  • Getting Started
    Guides很有用:

https://spring.io/guides#gs
  • 使用了JDBC的项目,必须编辑src/main/application.properties,加入数据库配置,否则会因为test failed而无法构建项目,举例:

spring.datasource.url=jdbc:mysql://localhost/database





spring.datasource.username=username





spring.datasource.password=password





spring.datasource.driver-class-name=com.mysql.jdbc.Driver





  • 想要直接输出内容而不使用模板,可以在控制器中使用@RestController,或在@Controller之后,加入@ResponseBody,当使用@Controller时,返回的字符串为src/main/resources/templates下的模板文件名,不要带扩展名
  • 默认情况下,不定义自己的ViewResolver时,如果路由(如/index)和模板文件重名(如index.html),会无法正确显示模板内容 ,并产生循环引用view的异常,最简单的解决方式是二者不要重名
  • 调式&运行:mvn spring-boot:run
  • 打包项目为jar::mvn package
  • 安装项目依赖:mvn install

let's encrypt及certobot-auto使用DNS验证方式注册证书

简要说明:使用manual插件,之后将letsencrypt验证所需DNS记录(TXT)加入DNS后,再进行验证

安装certbot的过程请看官方网站:https://certbot.eff.org/

[code language="bash"]ertbot-auto -d im.leiex.com --manual --preferred-challenges dns certonly[/code]

注意根据提示设定DNS的TXT记录,设定好后,再输入Enter确认

[code language="bash"]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

<code>Please deploy a DNS TXT record under the name
XXXXXX.im.leiex.com with the following value:</code>

XXXXXXXXX

&nbsp;

Before continuing, verify the record is deployed.


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Press Enter to Continue
[/code]

letsencrypt的证书有效期只有90天,通过验证后,不要移动证书的位置,在crontab中加入更新证书的命令

[code language="bash"]
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' &amp;&amp; /usr/bin/certbot-auto renew
[/code]

[wpedon id=230]

使用git合并上游repo到fork并上传代码

来源:https://help.github.com/articles/merging-an-upstream-repository-into-your-fork/

第一步,在fork下切换至需被合并的branch下
[code lang="bash"]git checkout master[/code]

第二步,拉取上游代码
[code lang="bash"]git pull https://github.com/ORIGINAL_OWNER ORIGINAL_REPOSITORY.git BRANCH_NAME[/code]

第三步,上传合并后的代码
[code lang="bash"]git push origin master[/code]

[wpedon id=230]

[工具推荐]makeself - Make self-extractable archives on Unix

makeself - Make self-extractable archives on Unix


makeself.sh is a small shell script that generates a self-extractable compressed tar archive from a directory. The resulting file appears as a shell script (many of those have a .run suffix), and can be launched as is. The archive will then uncompress itself to a temporary directory and an optional arbitrary command will be executed (for example an installation script). This is pretty similar to archives generated with WinZip Self-Extractor in the Windows world. Makeself archives also include checksums for integrity self-validation (CRC and/or MD5/SHA256 checksums).

The makeself.sh script itself is used only to create the archives from a directory of files. The resultant archive is actually a compressed (using gzip, bzip2, or compress) TAR archive, with a small shell script stub at the beginning. This small stub performs all the steps of extracting the files, running the embedded command, and removing the temporary files when done. All the user has to do to install the software contained in such an archive is to "run" the archive, i.e sh nice-software.run. I recommend using the ".run" (which was introduced by some Makeself archives released by Loki Software) or ".sh" suffix for such archives not to confuse the users, so that they will know they are actually shell scripts (with quite a lot of binary data attached to them though!).

I am trying to keep the code of this script as portable as possible, i.e it is not relying on any bash-specific features and only calls commands that are installed on any functioning UNIX-compatible system. This script as well as the archives it generates should run on any Unix flavor, with any compatible Bourne shell, provided of course that the compression programs are available.

As of version 2.1, Makeself has been rewritten and tested on the following platforms :
  • Linux (all distributions)

  • Sun Solaris (8 and above)

  • HP-UX (tested on 11.0 and 11i on HPPA RISC)

  • SCO OpenUnix and OpenServer

  • IBM AIX 5.1L

  • macOS (Darwin)

  • SGI IRIX 6.5

  • FreeBSD

  • UnicOS / Cray

  • Cygwin (Windows)


If you successfully run Makeself and/or archives created with it on another system, then please let me know!

Examples of publicly available archives made using makeself are :
  • Game patches and installers for Id Software games like Quake 3 for Linux or Return To Castle Wolfenstein ;

  • All game patches released by Loki Software for the Linux version of popular games ;

  • The nVidia drivers for Linux

  • The installer for the Linux version of Google Earth

  • The VirtualBox installers for Linux

  • The Makeself distribution itself ;-)

  • and countless others...

Important note for Apache users: By default, most Web servers will think that Makeself archives are regular text files and thus they may show up as text in a Web browser. The correct way to prevent this is to add a MIME type for this file format, like so (in httpd.conf) :

AddType application/x-makeself .run

Important note for certain GNU/Linux distributions: Archives created with Makeself prior to v2.1.2 were using an old syntax for the head and tail Unix commands that is being progressively obsoleted in their GNU forms. Therefore you may have problems uncompressing some of these archives. A workaround for this is to set the environment variable $_POSIX2_VERSION to enable the old syntax, i.e. :

export _POSIX2_VERSION=199209

Usage


The syntax of makeself is the following:
makeself.sh [args] archive_dir file_name label startup_script [script_args]

  • args are optional options for Makeself. The available ones are :
    • --version : Prints the version number on stdout, then exits immediately

    • --gzip : Use gzip for compression (the default on platforms on which gzip is commonly available, like Linux)

    • --bzip2 : Use bzip2 instead of gzip for better compression. The bzip2 command must be available in the command path. It is recommended that the archive prefix be set to something like '.bz2.run', so that potential users know that they'll need bzip2 to extract it.

    • --pbzip2 : Use pbzip2 instead of gzip for better and faster compression on machines having multiple CPUs. The pbzip2 command must be available in the command path. It is recommended that the archive prefix be set to something like '.bz2.run', so that potential users know that they'll need bzip2 to extract it.

    • --xz : Use xz instead of gzip for better compression. The xz command must be available in the command path. It is recommended that the archive prefix be set to something like '.xz.run' for the archive, so that potential users know that they'll need xz to extract it.

    • --lzo : Use lzop instead of gzip for better compression. The lzop command must be available in the command path. It is recommended that the archive prefix be set to something like .lzo.run for the archive, so that potential users know that they'll need lzop to extract it.

    • --lz4 : Use lz4 instead of gzip for better compression. The lz4 command must be available in the command path. It is recommended that the archive prefix be set to something like '.lz4.run' for the archive, so that potential users know that they'll need lz4 to extract it.

    • --pigz : Use pigz for compression.

    • --base64 : Encode the archive to ASCII in Base64 format instead of compressing (base64 command required).

    • --gpg-encrypt : Encrypt the archive using gpg -ac -z $COMPRESS_LEVEL. This will prompt for a password to encrypt with. Assumes that potential users have gpg installed.

    • --ssl-encrypt : Encrypt the archive using openssl aes-256-cbc -a -salt. This will prompt for a password to encrypt with. Assumes that the potential users have the OpenSSL tools installed.

    • --compress : Use the UNIX compress command to compress the data. This should be the default on all platforms that don't have gzip available.

    • --nocomp : Do not use any compression for the archive, which will then be an uncompressed TAR.

    • --complevel : Specify the compression level for gzip, bzip2, pbzip2, xz, lzo or lz4. (defaults to 9)

    • --notemp : The generated archive will not extract the files to a temporary directory, but in a new directory created in the current directory. This is better to distribute software packages that may extract and compile by themselves (i.e. launch the compilation through the embedded script).

    • --current : Files will be extracted to the current directory, instead of in a subdirectory. This option implies --notemp above.

    • --follow : Follow the symbolic links inside of the archive directory, i.e. store the files that are being pointed to instead of the links themselves.

    • --append (new in 2.1.x): Append data to an existing archive, instead of creating a new one. In this mode, the settings from the original archive are reused (compression type, label, embedded script), and thus don't need to be specified again on the command line.

    • --header : Makeself 2.0 uses a separate file to store the header stub, called makeself-header.sh. By default, it is assumed that it is stored in the same location as makeself.sh. This option can be used to specify its actual location if it is stored someplace else.

    • --copy : Upon extraction, the archive will first extract itself to a temporary directory. The main application of this is to allow self-contained installers stored in a Makeself archive on a CD, when the installer program will later need to unmount the CD and allow a new one to be inserted. This prevents "Filesystem busy" errors for installers that span multiple CDs.

    • --nox11 : Disable the automatic spawning of a new terminal in X11.

    • --nowait : When executed from a new X11 terminal, disable the user prompt at the end of the script execution.

    • --nomd5 and --nocrc : Disable the creation of a MD5 / CRC checksum for the archive. This speeds up the extraction process if integrity checking is not necessary.

    • --sha256 : Adds a SHA256 checksum for the archive. This is in addition to the MD5 / CRC checksums unless --nomd5 is also used.

    • --lsm file : Provide and LSM file to makeself, that will be embedded in the generated archive. LSM files are describing a software package in a way that is easily parseable. The LSM entry can then be later retrieved using the --lsm argument to the archive. An example of a LSM file is provided with Makeself.

    • --tar-extra opt : Append more options to the tar command line.

      For instance, in order to exclude the .git directory from the packaged archive directory using the GNU tar, one can use makeself.sh --tar-extra "--exclude=.git" ...

    • --keep-umask : Keep the umask set to shell default, rather than overriding when executing self-extracting archive.

    • --packaging-date date : Use provided string as the packaging date instead of the current date.

    • --license : Append a license file.

    • --nooverwrite : Do not extract the archive if the specified target directory already exists.

    • --header file : Specify the location of the header script file (default makeself-header.sh)

    • --help-header file : Add a header to the archive's --help output.


  • archive_dir is the name of the directory that contains the files to be archived

  • file_name is the name of the archive to be created

  • label is an arbitrary text string describing the package. It will be displayed while extracting the files.�

  • startup_script is the command to be executed from within the directory of extracted files. Thus, if you wish to execute a program contain in this directory, you must prefix your command with ./. For example, ./program will be fine. The script_args are additionnal arguments for this command.


Here is an example, assuming the user has a package image stored in a /home/joe/mysoft, and he wants to generate a self-extracting package named mysoft.sh, which will launch the "setup" script initially stored in /home/joe/mysoft :

makeself.sh /home/joe/mysoft mysoft.sh "Joe's Nice Software Package" ./setup

Here is also how I created the makeself.run archive which contains the Makeself distribution :

makeself.sh --notemp makeself makeself.run "Makeself by Stephane Peter" echo "Makeself has extracted itself"

Archives generated with Makeself can be passed the following arguments:
  • --keep : Prevent the files to be extracted in a temporary directory that will be removed after the embedded script's execution. The files will then be extracted in the current working directory and will stay here until you remove them.

  • --verbose : Will prompt the user before executing the embedded command

  • --target dir : Allows to extract the archive in an arbitrary place.

  • --nox11 : Do not spawn a X11 terminal.

  • --confirm : Prompt the user for confirmation before running the embedded command.

  • --info : Print out general information about the archive (does not extract).

  • --lsm : Print out the LSM entry, if it is present.

  • --list : List the files in the archive.

  • --check : Check the archive for integrity using the embedded checksums. Does not extract the archive.

  • --nochown : By default, a chown -R command is run on the target directory after extraction, so that all files belong to the current user. This is mostly needed if you are running as root, as tar will then try to recreate the initial user ownerships. You may disable this behavior with this flag.

  • --tar : Run the tar command on the contents of the archive, using the following arguments as parameter for the command.

  • --noexec : Do not run the embedded script after extraction.

  • --nodiskspace : Do not check for available disk space before attempting to extract.


Any subsequent arguments to the archive will be passed as additional arguments to the embedded command. You must explicitly use the -- special command-line construct before any such options to make sure that Makeself will not try to interpret them.

Startup Script


The startup script must be a regular Shell script.

Within the startup script, you can use the $USER_PWD variable to get the path of the folder from which the self-extracting script is executed. This is especially useful to access files that are located in the same folder as the script, as shown in the example below.

my-self-extracting-script.sh --fooBarFileParameter foo.bar

Maven Usage


Makeself is now supported by the following maven plugin makeself-maven-plugin. Please refer to project for usage and report any bugs in regards to maven plugin on that project.

License


Makeself itself is covered by the GNU General Public License (GPL) version 2 and above. Archives generated by Makeself don't have to be placed under this license (although I encourage it ;-)), since the archive itself is merely data for Makeself.

Contributing


I will gladly consider merging your pull requests on the GitHub repository. However, please keep the following in mind:
  • One of the main purposes of Makeself is portability. Do not submit patches that will break supported platforms. The more platform-agnostic, the better.

  • Please explain clearly what the purpose of the patch is, and how you achieved it.

Download


Get the latest official distribution here (version 2.4.0).

The latest development version can be grabbed from GitHub. Feel free to submit any patches there through the fork and pull request process.

Version history


  • v1.0: Initial public release

  • v1.1: The archive can be passed parameters that will be passed on to the embedded script, thanks to John C. Quillan

  • v1.2: Cosmetic updates, support for bzip2 compression and non-temporary archives. Many ideas thanks to Francois Petitjean.

  • v1.3: More patches from Bjarni R. Einarsson and Francois Petitjean: Support for no compression (--nocomp), script is no longer mandatory, automatic launch in an xterm, optional verbose output, and -target archive option to indicate where to extract the files.

  • v1.4: Many patches from Francois Petitjean: improved UNIX compatibility, automatic integrity checking, support of LSM files to get info on the package at run time..

  • v1.5.x: A lot of bugfixes, and many other patches, including automatic verification through the usage of checksums. Version 1.5.5 was the stable release for a long time, even though the Web page didn't get updated ;-). Makeself was also officially made a part of the Loki Setup installer, and its source is being maintained as part of this package.

  • v2.0: Complete internal rewrite of Makeself. The command-line parsing was vastly improved, the overall maintenance of the package was greatly improved by separating the stub from makeself.sh. Also Makeself was ported and tested to a variety of Unix platforms.

  • v2.0.1: First public release of the new 2.0 branch. Prior versions are officially obsoleted. This release introduced the --copy argument that was introduced in response to a need for the UT2K3 Linux installer.

  • v2.1.0: Big change : Makeself can now support multiple embedded tarballs, each stored separately with their own checksums. An existing archive can be updated with the --append flag. Checksums are also better managed, and the --nochown option for archives appeared.

  • v2.1.1: Fixes related to the Unix compression (compress command). Some Linux distributions made the insane choice to make it unavailable, even though gzip is capable of uncompressing these files, plus some more bugfixes in the extraction and checksum code.

  • v2.1.2: Some bug fixes. Use head -n to avoid problems with POSIX conformance.

  • v2.1.3: Bug fixes with the command line when spawning terminals. Added --tar--noexec for archives. Added --nomd5 and --nocrc to avoid creating checksums in archives. The embedded script is now run through "eval". The --info output now includes the command used to create the archive. A man page was contributed by Bartosz Fenski.

  • v2.1.4: Fixed --info output. Generate random directory name when extracting files to . to avoid problems. Better handling of errors with wrong permissions for the directory containing the files. Avoid some race conditions, Unset the $CDPATH variable to avoid problems if it is set. Better handling of dot files in the archive directory.

  • v2.1.5: Made the md5sum detection consistent with the header code. Check for the presence of the archive directory. Added --encrypt for symmetric encryption through gpg (Eric Windisch). Added support for the digest command on Solaris 10 for MD5 checksums. Check for available disk space before extracting to the target directory (Andreas Schweitzer). Allow extraction to run asynchronously (patch by Peter Hatch). Use file descriptors internally to avoid error messages (patch by Kay Tiong Khoo).

  • v2.1.6: Replaced one dot per file progress with a realtime progress percentage and a spining cursor. Added --noprogress to prevent showing the progress during the decompression. Added --target dir to allow extracting directly to a target directory. (Guy Baconniere)

  • v2.2.0: First major new release in years! Includes many bugfixes and user contributions. Please look at the project page on Github for all the details.

  • v2.3.0: Support for archive encryption via GPG or OpenSSL. Added LZO and LZ4 compression support. Options to set the packaging date and stop the umask from being overriden. Optionally ignore check for available disk space when extracting. New option to check for root permissions before extracting.

  • v2.3.1: Various compatibility updates. Added unit tests for Travis CI in the GitHub repo. New --tar-extra--untar-extra--gpg-extra--gpg-asymmetric-encrypt-sign options.

  • v2.4.0: Added optional support for SHA256 archive integrity checksums.

Links


  • Check out the "Loki Setup" installer, used to install many Linux games and other applications, and of which I am the co-author. Since the demise of Loki, I am now the official maintainer of the project, and it is now being hosted here on GitHub.

  • Bjarni R. Einarsson also wrote the setup.sh installer script, inspired by Makeself. Check it out !

Contact


This script was written by Stéphane Peter (megastep at megastep.org). Any enhancements and suggestions are welcome.

Contributions were included from John C. Quillan, Bjarni R. Einarsson, Francois Petitjean, Ryan C. Gordon, and many contributors on GitHub. If you think I forgot your name, don't hesitate to contact me.

This project is now hosted on GitHub. Feel free to submit patches and bug reports on the project page.

压缩go build/install生成的binary大小

方法1:使用ldflags去掉debug info,效果不明显,而且去掉了debug info,不推荐
[code lang="bash"]go build -ldflags="-w -s" xxx/main.go[/code]

方法2:使用upx压缩已编译的binary,需要时间较长,效果明显,推荐
[code lang="bash"]upx --brute bin/xxx[/code]

gocode无法自动补全的解决方法

看一下gocode的设定
[code lang="bash"]gocode set[/code]

确保配置如下:

[code lang="bash"]
propose-builtins false
lib-path "你的$GOPATH,以:分割,如果$GOPATH不行,试试$GOPATH/pkg"
custom-pkg-prefix ""
custom-vendor-dir ""
autobuild true
force-debug-output ""
package-lookup-mode "go"
close-timeout 1800
unimported-packages false
partials true
ignore-case false
class-filtering true
[/code]

关键点:

  • 正确的lib-path

  • autobuild为true

  • propose-builtins为false

  • package-lookup-mode为go

Windows下golang开发环境(32位+64位)搭建

 

  • 从http://www.golang.org下载golang的zip包


32位解压至D:\Go,64位解压至D:\Go64
  • 从http://tdm-gcc.tdragon.net/download下载tdm-gcc


32位解压至D:\TDM-GCC-32,64位解压至D:\mingw642
  • 新建两个bat文件,放至于C:\Windows下,用于32位开发环境及64位开发环境切換。


32位开发环境dev32.bat:

[code]REM Switch to 32-bit Development Environmentset GOROOT=D:\Go
set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;D:\Program Files\Git\bin;D:\Program Files\Git\cmd;D:\Go\bin;D:\TDM-GCC-32\bin
[/code]

64位开发环境dev64.bat:

[code]REM Switch to 64-bit Development Environment
set GOROOT=D:\Go64
set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;D:\Program Files\Git\bin;D:\Program Files\Git\cmd;D:\Go64\bin;D:\mingw64\bin[/code]

切换环境时,直接从cmd运行dev32或dev64即可
  • 对于git bash,使用同样的方式,以bash profile格式设定所需的GOROOT及PATH及可


32位开发环境/etc/devtools32

[code lang="bash"]#!/bin/sh
#Switch to 32-bit Development Envrionment
PATH='/usr/local/bin:/usr/bin:/bin:/c/ProgramData/Oracle/Java/javapath:/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/c/Windows/system32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0:/c/Program Files (x86)/Intel/OpenCL SDK/2.0/bin/x86:/c/Program Files (x86)/Intel/OpenCL SDK/2.0/bin/x64:/bin:/cmd:/d/Go/bin:/d/TDM-GCC-32/bin:/usr/bin/vendor_perl:/usr/bin/core_perl'
GOROOT=/d/Go
export PATH
export GOROOT[/code]

64位开发环境/etc/devtools64

[code lang="bash"]#!/bin/sh
#Switch to 64-bit Development Envrionment
PATH='/usr/local/bin:/usr/bin:/bin:/c/ProgramData/Oracle/Java/javapath:/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/c/Windows/system32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0:/c/Program Files (x86)/Intel/OpenCL SDK/2.0/bin/x86:/c/Program Files (x86)/Intel/OpenCL SDK/2.0/bin/x64:/bin:/cmd:/usr/bin/vendor_perl:/usr/bin/core_perl:/d/Go64/bin:/d/mingw64/bin'
GOROOT=/d/Go64
export PATH
export GOROOT[/code]

之后,使用bash的source命令切換环境即可任意切換到32或64位golang开发环境

[转]java对象转json, 数字精确出现丢失

现象

 java中的大数字比如18/19位的整数(long),转为json,输出到页面后,就出现精度丢失,如果数字再大些就会出现科学计数法。


这两个问题都不是json工具包(比如Gson)的问题,而是由于js存储大数字丢失精度引起。


1、精度丢失例子:当js表达整数时,最多表达15位数字,如果超过15位就会出现精度丢失问题。

援引js文档:

精度

整数(不使用小数点或指数计数法)最多为 15 位。


最后几位都变为0,丢失精度

var x = 1234567890123456999;console.log(x);
输出结果:1234567890123457000


2、

数字再大一些就会出现,科学计数法

var x = 123456789012345699999999;
console.log(x);
输出结果:1.234567890123457e+23


解决办法

台属性由数字类型改为字符串,转为json,传到前台就不会丢失了。

Magento前端页面数据显示-layout,template及block的使用

Magento的前端设计和平时多见的WEB MVC前端设计有很大不同,配置项较多,对于新手来说,不太容易理解,此文以一个简单的blog作为实例简单说明一下如何在Magento中开发自已想要的前端面页面

有三种方式可以实现按需显示页面数据:

新增/修改layout文件local.xml,之后在其中加入所需的配置替换content block,此方法简单方便,但local.xml可能还有别的模板在使用,迁移某个模块时,要按需从local.xml中提取所需内容更新至目标系统,对于不熟悉模块配置的人员来说很不方便

不修改layout配置,直接在controller中使用createBlock再append至content block(content block因为类型为text,因此不能直接setTemplate),此方法不需要更新layout,但增加了代码量,并且与Magento的MVC架构“controller不直接与view交互数据”不符,可能会造成维护上的麻烦

在模块中加入layout的updates配置,并新建模块所需layout文件,按照layout文件内容替换content,此方法是Magento官方模块所使用的方法,结构清析,模块独立性强,推荐使用

以下例子以第三种方式开发了一个简单的blog页面,实现了列表,新增,详情页

首先,在模块的config.xml中,在fronend中加入layout配置

[code lang="xml"]	<routers> <blog>
<use>standard</use>
<args>
<module>Etam_Blog</module>
<frontName>blog</frontName>
</args>
</blog>
</routers>
<layout>
<updates>
<!-- 此处的blog对应routers中的frontName -->
<blog>
<!-- layout文件的相对路径 -->
<file>blog.xml</file>
</blog>
</updates>
</layout>
[/code]

在layout目录下,新增blog.xml

[code lang="xml"]<?xml version="1.0"?>
<layout version="0.1.0">
<!-- default对应所有请求,因些这里加入了更换页面模板(root block)的代码,将页面模板更换为1列 -->
<default>
<reference name="root">
<action method="setTemplate">
<template>page/1column.phtml</template>
</action>
</reference>
</default>
<!-- 当url为blog/index/index时,以下的代码生效,将content block替换为想要被显示的内容,此处使用的是自已新增的block类,用于分页显示post列表 -->
<blog_index_index>
<reference name="content">
<block type="etam_blog/pager" name="blogs" template="etam/blog/index.phtml"/>
</reference>
</blog_index_index>
<!-- 当url为blog/index/show时,以下代码生效,此处使用系统block类,但根据setTemplate来达到显示所需内容的目地-->
<blog_index_show>
<reference name="content">
<block type="core/template" name="blog_info" template="etam/blog/show.phtml"/>
</reference>
</blog_index_show>
<!-- 当url为blog/index/new时,以下代码生效,此处使用系统block类,但根据setTemplate来达到显示所需内容的目地-->
<blog_index_new>
<reference name="content">
<block type="core/template" name="blog_info" template="etam/blog/new.phtml"/>
</reference>
</blog_index_new>
</layout>
[/code]

新增三个模板文件(template)index.phtml, new.phtml, show.phtml

post列表index.phtml

[code lang="xhtml"]<div class="tabs">
<dl class="collateral-tabs">
<dd class="tab-container">
<a href="<?php echo $this->getUrl("blog/index/new"); ?>"><button class="button">New Post</button></a>
</dd>
</dl>
</div>
<table width="100%" class="data-table" border="1">
<thead>
<th class="label" width="70%">Title</th>
<th class="label" width="15%">Post At</th>
<th class="label" width="15%">Post By</th>
</thead>
<tbody>
<?php
// Get Collection, load all data;
$posts = $this->getCollection();
$colstyle=0;
foreach ($posts as $p)
$customer = Mage::getModel("customer/customer")->load($p->getCustomer_id());
$colstyle++;
if ($customer)
?>
<tr class="<?php echo $colstyle%2?"odd":"even"; ?>">
<td class="data">
<a href="<?php echo $this->getUrl('blog/index/show', array('id' => $p->getId())); ?>">
<?php echo $p->getTitle(); ?>
</a>
</td>
<td class="data"><?php echo $p->getPost_at(); ?></td>
<td class="data"><?php echo $customer->getName(); ?></td>
</tr>
<?php


?>
</tbody>
</table>
<?php echo $this->getChildHtml('pager'); ?>
[/code]

新增post表单new.phtml

[code lang="xhtml"]<div class="tabs">
<dl class="collateral-tabs">
<dd class="tab-container">
<a href="<?php echo $this->getUrl('blog/index'); ?>">Return To Index</a>
</dd>
</dl>
</div>
<form id="post_new" method="post" action="<?php echo Mage::getUrl("blog/index/postNew"); ?>">
<div class="filedset">
<label class="required" for="title">
Title
</label>
<input id="title" name="title" class="input-text required-entry" required/>
</div>
<div class="filedset">
<label class="required" for="contents">
Contents
</label>
<div class="input-box">
<textarea name="contents" id="contents" cols="5" rows="3" class="required-entry"></textarea>
</div>
</div>
<div class="buttons-set">
<button type="submit" title="Submit Review" class="button">Post</button>
</div>
</form>[/code]

post详情show.phtml

[code lang="xhtml"]<?php
$id=Mage::app()->getRequest()->getParam("id");
if(!$id)
die("Illegal Call!");

$post=Mage::getModel("etam_blog/blog")->load($id);
?>
<div class="tabs">
<dl class="collateral-tabs">
<dd class="tab-container">
<a href="<?php echo $this->getUrl('blog/index'); ?>">Return To Index</a>
</dd>
</dl>
</div>
<table width="100%" class="data-table" border="1">
<thead>
<th class="label"><?php echo $post->getTitle(); ?></th>
</thead>
<tbody>
<tr>
<td class="data">
<?php echo $post->getContents(); ?>
</td>
</tr>
<tr>
<td class="data" >
Comments
</td>
</tr>
</tbody>
</table>[/code]

新增block配置至config.xml,class中内容为类名前缀

[code lang="xml"]<blocks>
<etam_blog>
<class>Etam_Blog_Block</class>
</etam_blog>
</blocks>
[/code]

新增的block类代码,注意这个block没有重载_toHtml方法,因为显示方式都定义在名为index.phtml的模板文件中,需要显示的数据用getCollection方法得到,分页控件使用Magento的html_pager block,在显示时只要使用$this->getChildHtml('pager')即可得到内容

[code lang="php"]class Etam_Blog_Block_Pager extends Mage_Core_Block_Template

protected $collection;
protected function _prepareLayout()

parent::_prepareLayout();
$this->collection = Mage::getModel("etam_blog/blog")->getCollection()->addFieldToFilter("status", "PUBLISHED")->setOrder("Post_at","DESC");
$pager = $this->getLayout()->createBlock('page/html_pager', 'custom.pager');
$pager->setAvailableLimit(array(50 => 50, 100 => 100, 'all' => 'all'));
$pager->setCollection($this->collection);
$this->setChild('pager', $pager);
return $this;

public function getCollection()
return $this->collection;

[/code]

最后是controller,因为所需的配置及数据源都已经用layout,template和block做好,代码很简单:

[code lang="php"]class Etam_Blog_IndexController extends Mage_Core_Controller_Front_Action

public function preDispatch()

parent::preDispatch();
$this->loadLayout();
//在页面最上方显示一个通知
$this->getLayout()->getBlock("global_notices")->setTemplate("etam/dev/info.phtml");

public function indexAction()

$this->getLayout()->getBlock("head")->setTitle(Mage::getStoreConfig("etam_blog_options/confs/blog_title"));
$this->renderLayout();

public function showAction()

$this->getLayout()->getBlock("head")->setTitle(Mage::getStoreConfig("etam_blog_options/confs/blog_title"));
$this->renderLayout();

public function newAction()

//只有已登陆础客才能新增post;
$loginUrl = Mage::helper('customer')->getLoginUrl();
if (!Mage::getSingleton('customer/session')->authenticate($this, $loginUrl))
$this->setFlag('', self::FLAG_NO_DISPATCH, true);

$this->renderLayout();

public function postNewAction()

//只有已登陆础客才能新增post;
$loginUrl = Mage::helper('customer')->getLoginUrl();
if (!Mage::getSingleton('customer/session')->authenticate($this, $loginUrl))
$this->setFlag('', self::FLAG_NO_DISPATCH, true);

try
$customer = Mage::getSingleton("customer/session");
$post = Mage::getModel("etam_blog/blog");
$post->setTitle(strip_tags($this->getRequest()->getParam("title")));
$post->setContents(strip_tags($this->getRequest()->getParam("contents")));
$post->setStatus("PUBLISHED");
$post->setCustomer_id($customer->getId());
$post->setPost_at(date('Y-m-d H:i:s'));
$post->save();
catch (Exception $e)
Mage::log($e->getMessage());

$this->_redirectUrl(Mage::getUrl("blog/index/index"));

[/code]

 

Magento Model之MySQL4类型资源

模块的config.xml

[code lang="xml"]<global> <models>
<etam_blog>
<version>0.1.0</version>
<!-- 此处定义Model类名前缀,在调用Mage::getModel(etam_blog/xxx)时,会组成Etam_Blog_Model_Xxx的类名 -->
<class>Etam_Blog_Model</class>
<!-- Model的资源类型,后面开新标签需定义资源配置详情 -->
<resourceModel>etam_blog_mysql4</resourceModel>
</etam_blog>
<!-- Model资源定义,实际与数据库进行交互行为的类 -->
<etam_blog_mysql4>
<!-- 资源Model类名前缀,在调用getResourceMode(etam_blog/xxx)l时,将组成类名Etam_Blog_Model_Mysql4_Xxx -->
<class>Etam_Blog_Model_Mysql4</class>
<!-- 资源Model实例,实际的数据表名,用于初始化资源Model,如果定义错误,Magento会报Null Connection。示例:在资源Model中调用_init("etam_blog/xxx")时,会尝试寻找此处有无标签为<xxx>的定义,并找到<table>中定义的表与之交互 -->
<entities>
<entity><table>etam_blog_entity</table></entity>
</entities>
</etam_blog_mysql4>
</models>
</global>
[/code]

Model类定义

[code lang="php"]class Etam_Blog_Model_Blog extends Mage_Core_Model_Abstract 
protected function _construct()

// 初始化资源类,取得类名Etam_Blog_Model_Mysql4_Blog
$this->_init("etam_blog/blog");

[/code]

资源Model类定义

[code lang="php"]class Etam_Blog_Model_Mysql4_Blog extends Mage_Core_Model_Mysql4_Abstract

protected function _construct()

//取得entity配置,对应到数据表etam_blog_entity
$this->_init("etam_blog/entity", "post_id");


[/code]

Collection集合类定义

[code lang="php"]class Etam_Blog_Model_Mysql4_Blog_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract 
protected function _construct()

// 此处初始化Model类
$this->_init("etam_blog/blog");

[/code]

controller中使用Model

[code lang="php"]public function testModelAction() 
// 取得URL参数
$params=$this->getRequest()->getParams();
// 从config.xml中查找<etam_blog>,根据配置组合为类名Etam_Blog_Model_Blog
$blog=Mage::getModel("etam_blog/blog");
// 根据参数载入资源,其中自动调用了getResourceModel,根据配置,此处会实例化一个Etam_Blog_Model_Mysql4_Blog对象,成功载入后,可对
$post=$blog->load($params['id']);
echo $post->getTitle();
// Collection的使用,取得所有记录所组成的Etam_Blog_Model_Blog对象数组
$posts=Mage::getModel("etam_blog/blog")->getCollection();
foreach($posts as $p)
echo $p->getContents();


[/code]

 

Magento商品挂图

商品挂图实际上是将商口的image相关attribute设定值,默认的image和small_image是85和86

Magento商品上图步骤:

制作csv文件,字段为:sku, image, small_imageimage埴写相对于media/import下的文件路径,不支持远程路径将制做好的csv文件通过Append Complex Data上传至系统在Cache管理处Flush Catalog Images Cache

 

数据库中商品存储图片查询:

SELECT

*

FROM

catalog_product_entity_varchar

WHERE

attribute_id IN (85, 86)

Magento商品属性设置及存储方式

所有商品属性都以attribute形式设定,如图片,size等

Attribute Set与attribute对应关系:

一个attribute set 对应多个attribute,可以设定该attribute的位置,如General, Meat Information等

使用自已创建的商品属性:

将需要的attribute和新创建的attribute set关联,在创建商品时选用指定新创建的attribute set即可

attribute可以设定为多种类型,如text,textarea,date,boolean,multiselect,dropdown(select)等

后台表:

Attriubte 设定,注意attribute_type_id,类型可在eav_entity_type表查到,backend type为数据库中存储类形,如varchar等,对应到catalog_product_entity_类型(以商品为例)表中(Entity)

select * from eav_attribute;

Attribute 选项(Attribute)

select * from eav_attribute_option;

Attribute 选项值(Value)

select * from eav_attribute_option_value;

Attribute Set设定

select * from eav_attribute_set;

Attribute set 与attribute关联关系

select * from eav_entity_attribute;

 

商品属性的存储是一个典型的E(entity)-A(attribute)-V(value)设计,遵循第三范式

Magento 1.x后台处维护的attribute/attribute set都是针对商品的,其它模块(如customer)需要自行从数据库配置自义定属性,attribute_type_id需使用eav_entity_type中已定义的类型ID

Magento系统配置的使用与自定义配置

系统配置的使用和存储方法

Magento的系统配置界面为System=>Configuration

在数据库中存储的数据表为core_config_data

在程序中获取系统配置的API为Mage::getStoreConfig(core_config_data中的path)

 

新增自定义系统配置

在模块的etc目录下新增system.xml,如:

[code lang="xml"]<?xml version="1.0" ?><config>
<tabs>
<etam_blog translate="label" module="etam_blog">
<label>Etam Blog</label>
<sort_order>1</sort_order>
</etam_blog>
</tabs>
<sections>
<etam_blog_options translate="label" module="etam_blog">
<label>Configurations</label>
<tab>etam_blog</tab>
<frontend_type>text</frontend_type>
<sort_order>1000</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<groups>
<confs>
<label>General</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<fields>
<blog_title>
<label>Blog Title</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</blog_title>
<show_posts>
<label>Number of posts shown per page</label>
<frontend_type>text</frontend_type>
<sort_order>2</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</show_posts>
<list_type>
<label>List type</label>
<frontend_type>select</frontend_type>
<source_model>etam_blog/ListTypes</source_model>
<sort_order>2</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</list_type>
</fields>
</confs>
<repls>
<label>Reply Settings</label>
<frontend_type>text</frontend_type>
<sort_order>2</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<fields>
<reply_email>
<label>Send Email to composer when get reply</label>
<frontend_type>checkbox</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</reply_email>
</fields>
</repls>
</groups>
</etam_blog_options>
</sections>
</config>[/code]

System.xml配置讲解

<tabs>为配置模块,展现为Configuration页面左侧块,如GENERAL, CATALOG等,此处是ETAM BLOG, Magento在显示时会将英文label转化为大写

<sections>为配置模块下的菜单项,一个section对应一个页面,如没有配置ACL,则magento会将页面跳转至404 Not Found

<groups>对应一个section页面中可折叠的配置组,其中包括一个或多个配置项

<fields>配置组中的配置项定义

<frontend_type>只有在fileds中才有意义,定义了该配置项对应的HTML控件类型

<source_model>配置项列表中对应的数据源Model,配置项列表的显示是调用该类的toOptionArray方法

增加ACL信息至config.xml

[code lang="xml"]<adminhtml>
<acl>
<resources>
<admin>
<children>
<system>
<children>
<config>
<children>
<etam_blog_options>
<title>Etam Blog Configurations</title>
</etam_blog_options>
</children>
</config>
</children>
</system>
</children>
</admin>
</resources>
</acl>
</adminhtml>
[/code]

config.xml中acl配置讲解

<adminhtml>后台配置块

<acl>ACL配置块

<children>URI路径分隔,如admin/system_config,则分为<admin><children><system><children><config>

<etam_blog_options>对应system.xml中的section名称

<title>配置页面中的标题

增加配置项候选列表Model

[code lang="php"]class Etam_Blog_Model_ListTypes extends Mage_Core_Model_Abstract
public function toOptionArray()
return array(
array('value'=>'TITLES_ONLY', 'label'=>Mage::helper('etam_blog')->__('Titles only')),
array('value'=>'FULL_CONTENTS', 'label'=>Mage::helper('etam_blog')->__('Full contents')),
array('value'=>'SUMMARY_ONLY', 'label'=>Mage::helper('etam_blog')->__('Sumary only'))
);

[/code]

配置项列表所使用的Model只需实现toOptionArray方法即可

Magento如何新增自定义的顾客属性

Magento 1.x 后台无顾客自定义属性配置页面,需直接操作数据库

定义attrribute,attribute_type_id为1(从eav_entity_type查得)

增加记录到customer_eav_attribute,is_visable定义是否显示

增加记录到customer_form_attribute

简单的JS倒计时代码

$(function () function countdown(dateString, callback) 
var timestamp = Date.parse(dateString), timer;
function timeDiff()
var t = timestamp - (new Date).getTime(),
d = time: t, day: '00', hour: '00', min: '00', sec: '00',
s = '';
if (t > 0)
s = '0' + parseInt(t / 1000 % 60);
d.sec = s.substr(s.length - 2); //秒
s = '0' + parseInt(t / 60000 % 60);
d.min = s.substr(s.length - 2); //分
s = '0' + parseInt(t / 3600000 % 24);
d.hour = s.substr(s.length - 2); //时
s = '0' + parseInt(t / 86400000 % 30);
d.day = s.substr(s.length - 2); //天

return d;

timer = setInterval(function ()
var result = timeDiff();
result.time > 0 ? callback(result) : clearInterval(timer);
, 1000);
callback(timeDiff());

var day = $('#theDay'), hour = $('#theHour'), min = $('#theMin'), sec = $('#theSec'),
endTime = '2012/12/21 00:00:00';
countdown(endTime, function (d)
day.text(Number(d.day));
hour.text(d.hour);
min.text(d.min);
sec.text(d.sec);
);
);

 

[留存备份]PHP SFTP下载文件代码

太忙,流程分析待补

代码来源:https://randomdrake.com/2012/02/08/listing-and-downloading-files-over-sftp-with-php-and-ssh2/



[code lang="php"]<?php
// Make our connection
$connection = ssh2_connect('ftp.somehost.com');
// Authenticate
if (!ssh2_auth_password($connection, 'username', 'password'))
throw new Exception('Unable to connect.');

// Create our SFTP resource
if (!$sftp = ssh2_sftp($connection))
throw new Exception('Unable to create SFTP connection.');

/**
* Now that we have our SFTP resource, we can open a directory resource
* to get us a list of files. Here we will use the $sftp resource in
* our address string as I previously mentioned since our ssh2://
* protocol allows it.
*/
$files = array();
$dirHandle = opendir("ssh2.sftp://$sftp/");
// Properly scan through the directory for files, ignoring directory indexes (. & ..)
while (false !== ($file = readdir($dirHandle)))
if ($file != '.' && $file != '..')
$files[] = $file;


/**
* Using our newly created list of files, we can go about downloading. We will
* open a remote stream and a local stream and write from one to the other.
* We will use error suppression on the fopen call to suppress warnings from
* not being able to open the file.
*/
if (count($files))
foreach ($files as $fileName)
// Remote stream
if (!$remoteStream = @fopen("ssh2.sftp://$sftp/$fileName", 'r'))
throw new Exception("Unable to open remote file: $fileName");

// Local stream
if (!$localStream = @fopen("/localdir/$fileName", 'w'))
throw new Exception("Unable to open local file for writing: /localdir/$fileName");

// Write from our remote stream to our local stream
$read = 0;
$fileSize = filesize("ssh2.sftp://$sftp/$fileName");
while ($read < $fileSize && ($buffer = fread($remoteStream, $fileSize - $read)))
// Increase our bytes read
$read += strlen($buffer);
// Write to our local file
if (fwrite($localStream, $buffer) === FALSE)
throw new Exception("Unable to write to local file: /localdir/$fileName");


// Close our streams
fclose($localStream);
fclose($remoteStream);

[/code]

 

php如何判断函数,类,类方法是否存在

(1)php判断系统函数或自己写的函数是否存在

bool function_exists ( string $function_name ) 判断函数是否已经定义,例如:

if(function_exists('curl_init'))	curl_init();
else
echo 'CUrl extension is not installed';

2)php判断类是否存在

bool class_exists ( string $class_name [, bool $autoload = true ] ) 检查一个类是否已经定义,一定以返回true,否则返回false,例如:

if(class_exists('MySQL'))
$myclass=new MySQL();

(3)php判断类里面的某个方法是否已经定义

bool method_exists ( mixed $object , string $method_name ) 检查类的方法是否存在,例如:

$directory=new Directory;
if(!method_exists($directory,'read'))
echo 'Undefined method: read';

Linux release using port

Code:

fuser -k -n *protocol portno* Example: fuser -k -n tcp 37

快速排序 (Hoare & Lomuto)

Hoare 版 (最初版)


[code lang="c"]void qsort_hoare(int *ary,int start,int end)
if(start>=end)
return;

int left=start+1;
int right=end;
while(left<right)
while(ary[left]<ary[start] && left<=end)
left++;

while(ary[right]>=ary[start] && right>start)
right--;

if(left<right)
swap(&ary[left],&ary[right]);


/* Insert the pivot into right place; */
swap(&ary[right],&ary[start]);
qsort_hoare(ary,start,right-1);
qsort_hoare(ary,right+1,end);
[/code]

[code]Lomuto 版 (算法导论)[/code]



[code lang="c"]void qsort(int *ary,int start,int end)
if(start>=end)
return;

int b=start+1;
int i=start+1;
for(i=start+1; i<=end; i++)
if(ary[i]<ary[start])
swap(&ary[b],&ary[i]);
b++;


swap(&ary[b-1],&ary[start]);
qsort(ary,start,b-2);
qsort(ary,b,end);
[/code]

[转]PHP中Session引起的脚本阻塞问题解决办法

原文地址:http://www.jb51.net/article/48805.htm


解决session阻塞问题的办法:在session操作完成后调用session_write_close()即可避免此问题;



案例一:


使用session过程中,在开启session后,同一浏览器,执行同一程序,不同页面会被锁。不同浏览器不会出现这种情况。


  疑问:是不是session_start导致了阻塞?


   于是,我写了几个页面测试了一下,发现是session导致了阻塞,而其他两种情况不会造成阻塞。


   查了下PHP的Bug列表,发现有人提出了这个问题:


复制代码 代码如下:


Description:
------------
Calling session_start() appears to wait until other scripts have exited


 


that are using the same session. My guess is the 1st request locks the
session file for exclusive use, and the second request blocks until it
can open it.


 


    PHP官方的回复是:


复制代码 代码如下:


Thank you for taking the time to write to us, but this is not a bug.This is expected, the session file is locked to avoid corruption.


 


    结合了PHP的Session机制,找到了阻塞的原因。由于PHP的Session信息是写入文件的,1个客户端占有1个session文件。因此,当 session_start被调用的时候,该文件是被锁住的,而且是以读写模式锁住的(因为程序中可能要修改session的值),这样,第2次调用 session_start的时候就被阻塞了。


    最简解决方法:


    查了PHP的手册,发现一个session_write_close函数,作用是Write session data and end session,也就是写session的数据,同时关闭这个session。因此,我们可以在用完session之后,调用这个函数关闭session 文件即可解除锁定。一般,session是用来记录用户身份信息的,以便PHP进行身份认证,因此完全可以将session的读写放在页面刚开始执行的时 候,在执行完以后,马上调用session_write_close函数即可。



案例二:


上回说要改opencart其实是给opencart加一个抓取淘宝上的产品的功能,但是弄完后发现一个问题,就是当脚本在抓取的时候,因为这个过 程比较慢,这个时候其他所有脚本的执行都被阻塞了,直到抓取完其他脚本才能依次执行。研究了半天没有结果,在知乎上问了下可能是session的问题,需 要调用session_write_close()来解决,那么这个session_write_close()是干嘛用的呢,手册上这样写的:


复制代码 代码如下:



结束当前session,保存session数据。


 


session数据通常会在脚本执行结束后被保存而并不需要调用session_write_close(),但是为保护session在任何时候 都只能被一个脚本执行写操作,session的数据会被锁住。当同时使用框架网页和session时你会发现,框架里的网页会因为这个个锁定而逐个载入。 你可以通过在所有的session数据修改保存结束后马上结束session来加快载入时间。


 


这就很好的解释了为什么我的抓取脚本会阻塞其他页面的原因。所以,如果你有一个需要执行时间比较长并用到session的ajax请求的话,就需要在服务器端调用session_write_close(),不然你的其他页面就都会被挂起直到请求结束!!!


 

MySQL函数的正确调用顺序,彻底解决内存泄露问题

在主线程中: 在使用其他mysql函数之前调用 mysql_library_init

退出主线程的时候调用 mysql_library_end

在子线程中: 使用 mysql_init(mysql_thread_init会被该函数自动调用)

结束的时候记得调用 mysql_close mysql_thread_end

使用netstat查看系统中的socket状态

代码:


[code lang="bash"]netstat -n | awk '/^tcp/ ++S[$NF] END for(a in S) print a, S[a]'[/code]

 

使用STL容器类的一些注意事项

1. 不要随便调用clear()方法,该方法不会自动检查元素合法性,随便调用容易引起Segment Fault

2. 判断是否为空请使用empty()而不是判断size()的大小是否为0

3. 如果存的是指针,那么需要自己释放内存,如果是存储的引用,则会自动析构。这里推荐使用引用,因为C++中的引用是不会复制内存的,速度非常快。

4. Memory leak的解决方法。當無法使用smart pointer時,如double free。可使用一個unsigned long來保存指針地址,在析构中對該指針进行delete操作以完全释放內存。

MySQL查锁定的表并解锁

查open tables

[code lang="sql"]
SHOW OPEN TABLES WHERE in_use>0;[/code]

查Process List


[code lang="sql"]
SHOW FULL PROCESSLIST;[/code]

查Transactions


[code lang="sql"]
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;[/code]

杀死进程


[code lang="sql"]
KILL process_ID/transaction_process_ID;[/code]

C中的位域(Bit Fields)

声明结构体时,可使用位域

如(以下以x86为例):


[code lang="cpp"]
struct BitField
unsigned int a:8;
unsigned int b:4;
unsigned int c:4;

[/code]

sizeof(BitField)为4


[code lang="cpp"]
struct BitField
unsigned int a:4;
unsigned int :0;
unsigned int b:8;

[/code]

sizeof(BitField)为8


使用规则:


Bit Filed不能跨字节,也就是最大不可以超过8,也就是1Byte,超过时可编译,但只能用到1Byte
使用0位域来使用新的字节,在一个字节不够用时使用
在不使用pack时,偏移为整个结构体最大成员占用的字节数,整个结构体为最大成员占用字节的整数倍

位域操作在开发系统内核/驱动程序时尤其好用。如CR3寄存器等结构,可以直接使用C struct模拟。

GDB使用小技巧

  • 设置环境变量,如LD_LIBRARY_PATH
set env LD_LIBRARY_PATH=/opt/lib
  • 设置运行参数
set args --db=mysql://localhost/db
  • 设置日志文件。分两步,第一步,设置文件名称;第二步,打开日志记录
set logging file output.log
set logging on