diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..5c3ac53
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eaa19e7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target/*
+.idea/*
diff --git a/.project b/.project
new file mode 100644
index 0000000..8817c2e
--- /dev/null
+++ b/.project
@@ -0,0 +1,48 @@
+
+
+ svnadmin
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.springframework.ide.eclipse.boot.validation.springbootbuilder
+
+
+
+
+
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.wst.common.modulecore.ModuleCoreNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.wst.common.project.facet.core.nature
+ org.eclipse.wst.jsdt.core.jsNature
+
+
diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope
new file mode 100644
index 0000000..2418123
--- /dev/null
+++ b/.settings/.jsdtscope
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..29abf99
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6e80039
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..c8a6ba1
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..6d59853
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..ca8d96f
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000..04cad8c
--- /dev/null
+++ b/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f7baecd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "{}" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright 2017 微笑风采
+
+ Licensed 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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d73dbb4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# SvnAdmin frok from `https://git.oschina.net/hpboys/svnadmin.git`
+
+## 说明:本系统用于配合silksvn服务器使用,不支持Visual SvnServer。
+
+#### 致力于成为一个安全流畅,极简可靠的SVN管理工具
+> 主要功能
+- SVN仓库创建,管理;
+- SVN用户,用户组创建,管理;
+- SVN资源权限授权;
+- 用户权限查看,密码更改;
+- SVN仓库支持多库模式;
+
+> 获取老司机的带路:
+
+
+
+
+> 一、使用源码开发部署步骤:
+1. 下载项目源码;
+1. 找到文件 test\resources\svnadmin_init.sql 进行执行初始化;
+1. 默认root账户:root/root
+1. 删除所有账户,进行登录,则可以重新初始化管理员账号;
+1. SVN认证账户和登录账户默认一致;
+
+
+> 二、使用部署包直接部署步骤:
+1. 下载最新部署包([点此下载]());TODO
+1. 找到文件 sql\svnadmin_init.sql 进行执行初始化;
+1. 配置数据库连接信息,配置文件位置:WEB-INF/classes/jdbc.properties
+1. 部署到tomcat等Web容器中即可;环境推荐JDK1.8 / Tomcat8
+1. 默认root账户:root/root
+1. 删除所有账户,进行登录,则可以重新初始化管理员账号;
+1. SVN认证账户和登录账户默认一致;
+
+
+> 三、使用多库启动模式:
+TODO
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..758eb52
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,336 @@
+
+ 4.0.0
+ org.svnadmin
+ svnadmin
+ 3.0.6
+ war
+
+
+ svnadmin
+ UTF-8
+
+ true
+
+ 1.7.6
+ 3.2.18.RELEASE
+ 4.8.2
+ 2.6
+ 1.4
+ 1.5.5
+ 2.0.1
+ 1.1.1
+ 1.2.16
+
+ 1.9.13
+
+ 6.0.37
+
+ 1.2
+
+ 7.0
+
+ 6.0.37
+
+ 5.1.14
+ 10.2.0.3.0
+
+
+ 5.2.4.Final
+
+
+
+
+
+ javax
+ javaee-api
+ ${javaee-api.version}
+
+
+
+ jstl
+ jstl
+ ${jstl.version}
+
+
+
+ org.apache.tomcat
+ servlet-api
+ ${servlet-api-version}
+
+
+
+ org.apache.tomcat
+ jsp-api
+ ${jsp-api-version}
+
+
+
+ org.tmatesoft.svnkit
+ svnkit
+ ${svnkit.version}
+
+
+
+
+ org.springframework
+ spring-core
+ ${spring.version}
+
+
+ org.springframework
+ spring-beans
+ ${spring.version}
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+
+ org.apache.geronimo.specs
+ geronimo-annotation_1.0_spec
+ 1.1.1
+
+
+
+
+ org.springframework
+ spring-aop
+ ${spring.version}
+
+
+ org.aspectj
+ aspectjweaver
+ 1.6.8
+
+
+ cglib
+ cglib-nodep
+ 2.2
+
+
+
+
+ org.springframework
+ spring-orm
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-web
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-webmvc
+ ${spring.version}
+
+
+
+
+ org.springframework
+ spring-jdbc
+ ${spring.version}
+
+
+
+
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+ ${jackson-version}
+
+
+
+ commons-lang
+ commons-lang
+ ${commons-lang.version}
+ jar
+
+
+ commons-dbcp
+ commons-dbcp
+ ${commons-dbcp.version}
+
+
+
+ commons-pool
+ commons-pool
+ ${commons-pool.version}
+ jar
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+
+
+ log4j
+ log4j
+ ${log4j.version}
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${jdbc.mysql.version}
+ jar
+ runtime
+
+
+
+
+ org.hibernate
+ hibernate-validator
+ ${hibernate-validator.version}
+
+
+
+
+
+
+
+
+ svnkit_repository
+
+ true
+
+
+ false
+
+ http://maven.svnkit.com/maven2/
+
+
+
+
+ ${war.name}
+
+
+ src/main/resources
+ true
+
+ version.properties
+
+
+
+ src/main/resources
+ false
+
+ version.properties
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 2.1.1
+
+ ${war.archiveClasses}
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ 1.8
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 2.5
+
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.1.2
+
+
+ attach-sources
+ package
+
+ jar
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+ true
+
+ ${project.build.outputDirectory}/META-INF/zip.xml
+
+
+
+
+ package
+
+ single
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/common/annotation/AdminAuthPassport.java b/src/main/java/org/svnadmin/common/annotation/AdminAuthPassport.java
new file mode 100644
index 0000000..12b6e18
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/annotation/AdminAuthPassport.java
@@ -0,0 +1,22 @@
+package org.svnadmin.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @描述: 管理员未登录可访问资源标识.
+ * @作者: Zoro.
+ * @创建时间: 2016-04-21 22:24.
+ * @版本: 1.0.0.
+ */
+@Documented
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AdminAuthPassport {
+ boolean validate() default true;
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/common/annotation/AuthPassport.java b/src/main/java/org/svnadmin/common/annotation/AuthPassport.java
new file mode 100644
index 0000000..11b1b62
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/annotation/AuthPassport.java
@@ -0,0 +1,22 @@
+package org.svnadmin.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @描述: 用户未登录可访问资源标识.
+ * @作者: Zoro.
+ * @创建时间: 2016-04-21 22:24.
+ * @版本: 1.0.0.
+ */
+@Documented
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AuthPassport {
+ boolean validate() default true;
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/common/entity/PageBean.java b/src/main/java/org/svnadmin/common/entity/PageBean.java
new file mode 100644
index 0000000..77b091f
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/entity/PageBean.java
@@ -0,0 +1,195 @@
+package org.svnadmin.common.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName: PageBean
+ * @Description: 分页工具类
+ * @author hpboys
+ * @date 2015年6月6日 下午3:34:22
+ * @version V1.0
+ * @param
+ */
+public class PageBean implements Serializable {
+ private int currentPage;//第几页,即当前页
+ private int pageSize;//每页大小
+ private int beginRow;//开始取的行数
+ private int pageCount;//共几页
+ private int recordCount;//记录总数
+ private List dataList;//数据
+ private Map footer;//底部统计区
+
+ private int startPage;//开始页码数
+ private int endPage;//结束页码数
+ private List pages;//动态页码
+ private int maxShowPageNum = 6;//最大显示页码数
+ private Map queryMap;//查询参数
+ private String sqlWhere;
+
+ public PageBean(){}
+
+ public PageBean(int pageNumber, int pageSize) {
+ this.currentPage = pageNumber;
+ this.pageSize = pageSize;
+ }
+
+ public PageBean(int pageNumber, int pageSize,int maxShowPageNum) {
+ this.currentPage = pageNumber;
+ this.pageSize = pageSize;
+ this.maxShowPageNum = maxShowPageNum;
+ }
+
+ private void initPages(){
+ int startPage = 0;
+ int endPage = 0;
+ int ban_page_Num = (this.maxShowPageNum % 2)==0? (this.maxShowPageNum / 2):(this.maxShowPageNum / 2)+1;
+ if ( this.currentPage <= ban_page_Num) {
+ // 如果当前页码小于显示最大页码数的一半
+ startPage = 1;
+ if (pageCount <= this.maxShowPageNum) {
+ endPage = pageCount+1;
+ } else {
+ endPage = this.maxShowPageNum;
+ }
+ } else if ( this.currentPage > (pageCount - ban_page_Num) ) {
+ // 如果当前页面大于最大页数-显示最大页码数的一半
+ startPage = pageCount - this.maxShowPageNum;
+ endPage = pageCount;
+ } else {
+ // 否则,保持当前页码在输出页码数的中间
+ startPage = this.currentPage - ban_page_Num + 1;
+ endPage = this.currentPage + ban_page_Num;
+ }
+ if (startPage < 1) startPage = 1;
+ if (endPage > pageCount) endPage = pageCount;
+ this.startPage = startPage;
+ this.endPage = endPage;
+ this.pages = new ArrayList();
+ for (int i = this.startPage; i <= this.endPage; i++) {
+ this.pages.add(i);
+ }
+ }
+
+
+ public int getCurrentPage() {
+ return currentPage;
+ }
+ public void setCurrentPage(int currentPage) {
+ this.currentPage = currentPage;
+ }
+ public int getPageSize() {
+ return pageSize;
+ }
+ public void setPageSize(int pageSize) {
+ this.pageSize = pageSize;
+ }
+ public int getPageCount() {
+ return pageCount;
+ }
+
+ public void setPageCount(int recordCount) {
+ if(recordCount%pageSize==0){
+ this.pageCount = recordCount/pageSize;
+ }else{
+ this.pageCount = recordCount/pageSize+1;
+ }
+ initPages();
+ }
+ public int getRecordCount() {
+ return recordCount;
+ }
+ public void setRecordCount(int recordCount) {
+ this.recordCount = recordCount;
+ }
+ public List getDataList() {
+ if(null==dataList){
+ return new ArrayList(0);
+ }
+ return dataList;
+ }
+ public void setDataList(List dataList) {
+ this.dataList = dataList;
+ }
+
+ public Map getFooter() {
+ return footer;
+ }
+
+ public void setFooter(Map footer) {
+ this.footer = footer;
+ }
+
+ public int getStartPage() {
+ return this.startPage;
+ }
+
+ public void setStartPage(int startPage) {
+ this.startPage = startPage;
+ }
+
+ public int getEndPage() {
+ return endPage;
+ }
+
+ public void setEndPage(int endPage) {
+ this.endPage = endPage;
+ }
+
+ public void setPages(List pages) {
+ this.pages = pages;
+ }
+
+ public List getPages() {
+ return pages;
+ }
+
+ public int getMaxShowPageNum() {
+ return maxShowPageNum;
+ }
+
+ public void setMaxShowPageNum(int maxShowPageNum) {
+ this.maxShowPageNum = maxShowPageNum;
+ }
+
+ public int getBeginRow() {
+ this.beginRow = (this.getCurrentPage()<=1?0:this.getCurrentPage()-1)*this.getPageSize();
+ return this.beginRow;
+ }
+
+ public void setQuery(String queryKey,String queryVal) {
+ if(this.queryMap == null){
+ this.queryMap = new HashMap();
+ }
+ this.queryMap.put(queryKey,queryVal);
+ }
+
+ public void setQueryMap(Map queryMap) {
+ this.queryMap = queryMap;
+ }
+
+ public Map getQueryMap() {
+ return queryMap;
+ }
+
+ /**
+ * @Description: 传入查询参数KEY,得到值
+ * @return String 返回类型
+ */
+ public String get(String key){
+ return this.queryMap==null? null:this.queryMap.get(key);
+ }
+
+ public String getSqlWhere() {
+ return sqlWhere;
+ }
+
+ public void setSqlWhere(String sqlWhere) {
+ this.sqlWhere = sqlWhere;
+ }
+
+
+}
diff --git a/src/main/java/org/svnadmin/common/entity/PushMsg.java b/src/main/java/org/svnadmin/common/entity/PushMsg.java
new file mode 100644
index 0000000..32bfd5e
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/entity/PushMsg.java
@@ -0,0 +1,112 @@
+package org.svnadmin.common.entity;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PushMsg implements Serializable {
+ private Object info;// 主信息
+ private Boolean status;// 状态
+ private String code;//CODE状态
+ private int arg1;//附加值
+ private Map attr = new HashMap();
+
+ public PushMsg() {}
+
+ public PushMsg(Boolean status) {
+ this.status = status;
+ }
+
+ public PushMsg(String info, Boolean status) {
+ this.info = info;
+ this.status = status;
+ }
+
+ public PushMsg(Object info, Boolean status) {
+ this.info = info;
+ this.status = status;
+ }
+
+ public PushMsg(String info, String code) {
+ this.info = info;
+ this.code = code;
+ }
+
+ public PushMsg(String info, Boolean status, String code) {
+ this.info = info;
+ this.status = status;
+ this.code = code;
+ }
+
+ public PushMsg(Object info, String code) {
+ this.info = info;
+ this.code = code;
+ }
+
+ public PushMsg(Object info,Boolean status,Object... entrys){
+ this.arg1 = 0;
+ this.info = info;
+ this.status = status;
+ for (int i = 0; i < entrys.length; i+=2) {
+ this.getAttr().put(String.valueOf(entrys[i]), entrys[i+1]);
+ }
+ }
+
+ public Object getInfo() {
+ return info;
+ }
+
+ public void setInfo(Object info) {
+ this.info = info;
+ }
+
+ public Boolean getStatus() {
+ return status;
+ }
+
+ public void setStatus(Boolean status) {
+ this.status = status;
+ }
+
+ public int getArg1() {
+ return arg1;
+ }
+
+ public void setArg1(int arg1) {
+ this.arg1 = arg1;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ /**
+ * 加入反馈属性
+ * @return
+ */
+ public Map getAttr() {
+ return attr;
+ }
+
+ public void setAttr(Map attr) {
+ this.attr = attr;
+ }
+
+ /**
+ * 得到消息对象
+ * @param info
+ * @param status
+ * @return
+ */
+ public static PushMsg getPushMsg(String info, Boolean status) {
+ PushMsg msg = new PushMsg();
+ msg.setInfo(info);
+ msg.setStatus(status);
+ return msg;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/common/mapper/SimpleDateFormatMapper.java b/src/main/java/org/svnadmin/common/mapper/SimpleDateFormatMapper.java
new file mode 100644
index 0000000..fb8982e
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/mapper/SimpleDateFormatMapper.java
@@ -0,0 +1,38 @@
+package org.svnadmin.common.mapper;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.CustomSerializerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * 解决SpringMVC使用@ResponseBody返回json时,
+ * 日期格式默认显示为时间戳的问题。需配合使用
+ * @author Zoro
+ * @date 2016-02-29 下午04:17:52
+ */
+@Component("simpleDateFormatMapper")
+public class SimpleDateFormatMapper extends ObjectMapper {
+
+ private final static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+ public SimpleDateFormatMapper() {
+ CustomSerializerFactory factory = new CustomSerializerFactory();
+ factory.addGenericMapping(Date.class, new JsonSerializer() {
+ @Override
+ public void serialize(Date value, JsonGenerator jsonGenerator,
+ SerializerProvider provider) throws IOException, JsonProcessingException {
+ SimpleDateFormat sdf = new SimpleDateFormat(DATETIME_FORMAT);
+ jsonGenerator.writeString(sdf.format(value));
+ }
+ });
+ this.setSerializerFactory(factory);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/common/util/HttpUtils.java b/src/main/java/org/svnadmin/common/util/HttpUtils.java
new file mode 100644
index 0000000..5f7f73d
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/util/HttpUtils.java
@@ -0,0 +1,255 @@
+package org.svnadmin.common.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.log4j.Logger;
+
+/**
+ * @ClassName: HttpUtils
+ * @Description: Http网络操作
+ * @author hpboys
+ * @date 2015年6月10日 下午2:12:33
+ * @version V1.0
+ */
+public class HttpUtils {
+ private static Logger logger = Logger.getLogger(HttpUtils.class);
+
+ /**
+ * @Title: getDoGetFullUrl
+ * @Description: 得到GET请求网站URL
+ * @return String 返回类型
+ */
+ public static String getGetFullUrl(String url,String... postParams){
+ if(postParams!=null){
+ for (int i = 0; i < postParams.length; i=i+2) {
+ if(!url.contains("?") && i==0){
+ url += "?"+postParams[i]+"="+postParams[i+1];
+ }else{
+ url += "&"+postParams[i]+"="+postParams[i+1];
+ }
+ }
+ }
+ return url;
+ }
+
+ /**
+ * @Title: getDoGetFullUrl
+ * @Description: 得到GET请求网站URL
+ * @return String 返回类型
+ */
+ public static String getGetFullUrl(String url,Map postParams){
+ if(postParams!=null){
+ int i = 0;
+ for (String key : postParams.keySet()) {
+ if(!url.contains("?") && i==0){
+ url += "?"+key+"="+String.valueOf(postParams.get(key));
+ }else{
+ url += "&"+key+"="+String.valueOf(postParams.get(key));
+ }
+ i++;
+ }
+ }
+ return url;
+ }
+
+ /**
+ * 将请求中的参数封装成Map
+ * @param request Http请求对象
+ * @return 将所有请求参数封装为Map集合并返回
+ */
+ public static Map getParams(HttpServletRequest request){
+ Map params = new HashMap();
+ for (String key : request.getParameterMap().keySet()) {
+ params.put(key, HttpUtils.urlDecode(request.getParameter(key), "UTF-8"));
+ }
+ return params;
+ }
+
+ /**
+ * 将请求中的参数封装成Map
+ * @param request Http请求对象
+ * @return 将所有请求参数封装为Map集合并返回
+ */
+ public static Map getParamters(HttpServletRequest request){
+ Map params = new HashMap();
+ try {
+ for (String key : request.getParameterMap().keySet()) {
+ String value = request.getParameter(key);
+ value = java.net.URLDecoder.decode(value, "UTF-8");
+ params.put(key, value);
+ }
+ } catch (UnsupportedEncodingException e) {
+ }
+ return params;
+ }
+
+ /**
+ * 将请求中的参数封装成Map
+ * @param request Http请求对象
+ * @return 将所有请求参数封装为Map集合并返回
+ */
+ public static Map getParams(ServletRequest request){
+ Map params = new HashMap();
+ for (String key : request.getParameterMap().keySet()) {
+ params.put(key, HttpUtils.urlDecode(request.getParameter(key), "UTF-8"));
+ }
+ return params;
+ }
+
+ /**
+ * 将Session域中的参数封装成Map
+ * @param session HttpSession请求对象
+ * @return
+ */
+ public static Map getParams(HttpSession session) {
+ Map params = new HashMap();
+ Enumeration enumeration = session.getAttributeNames();
+ while(enumeration.hasMoreElements()){
+ String key = enumeration.nextElement();
+ params.put(key, session.getAttribute(key));
+ }
+ return params;
+ }
+
+ /**
+ * 得到客户端IP地址
+ * @param request
+ * @return
+ */
+ public static String getRemoteIpAddr(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ return ip;
+ }
+
+ /**
+ * isAjaxRequest:判断请求是否为Ajax请求.
+ * @param request 请求对象
+ * @return boolean
+ */
+ public static boolean isAjaxRequest(HttpServletRequest request){
+ String header = request.getHeader("X-Requested-With");
+ boolean isAjax = "XMLHttpRequest".equals(header) ? true:false;
+ return isAjax;
+ }
+
+ /**
+ * 进行UrlDecode解码
+ * @param text 字符串
+ * @param charset 编码
+ * @return
+ */
+ public static String urlDecode(String text, String charset) {
+ try {
+ return URLDecoder.decode(text,charset);
+ } catch (Exception e) {
+ return text;
+ }
+ }
+
+ /**
+ * 进行urlEncode加码
+ * @param text 字符串
+ * @param charset 编码
+ * @return
+ */
+ public static String urlEncode(String text, String charset) {
+ try {
+ return URLEncoder.encode(text,charset);
+ } catch (Exception e) {
+ return text;
+ }
+ }
+
+ /**
+ * @Title: inputStream2String
+ * @Description: 将InputStream转换为字符串
+ * @return String 返回类型
+ */
+ public static String inputStream2String(InputStream is) {
+ int i = -1;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ while ((i = is.read()) != -1) {
+ baos.write(i);
+ }
+ String content = baos.toString();
+ baos.flush();
+ baos.close();
+ return content;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * @Description: 后台进行POST请求(请写在代码执行结尾)
+ * @return void 返回类型
+ */
+ public static void doBgPostReq(HttpServletResponse response,String postUrl,Map paramMap) throws IOException {
+ response.setContentType( "text/html;charset=utf-8");
+ PrintWriter out = response.getWriter();
+ out.println("");
+ out.println("");
+ }
+
+ /**
+ * 得到访问请求根域名
+ * @param request
+ * @return
+ */
+ public static String getRootHost(HttpServletRequest request){
+ return request.getRequestURL().toString().split(request.getRequestURI())[0];
+ }
+
+ /**
+ * 得到访问请求项目根域名
+ * @param request
+ * @return
+ */
+ public static String getSysHost(HttpServletRequest request){
+ return request.getRequestURL().toString().split(request.getRequestURI())[0] + request.getContextPath();
+ }
+
+ /**
+ * 将请求中的参数封装成Map,并去掉前后空格
+ * @param request Http请求对象
+ * @return 将所有请求参数封装为Map集合并返回
+ */
+ public static Map getTrimedParams(HttpServletRequest request){
+ Map params = new HashMap();
+ for (String key : request.getParameterMap().keySet()) {
+ params.put(key, HttpUtils.urlDecode(request.getParameter(key), "UTF-8").trim());
+ }
+ return params;
+ }
+}
diff --git a/src/main/java/org/svnadmin/common/util/PrintUtils.java b/src/main/java/org/svnadmin/common/util/PrintUtils.java
new file mode 100644
index 0000000..c47ef71
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/util/PrintUtils.java
@@ -0,0 +1,139 @@
+package org.svnadmin.common.util;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.web.method.HandlerMethod;
+
+/**
+ * @author hpboys
+ * @version V1.0
+ * @ClassName: PrintUtils
+ * @Description: 打印信息工具类
+ * @date 2015年6月13日 下午2:04:43
+ */
+public class PrintUtils {
+
+ public static Logger logger = Logger.getLogger(PrintUtils.class);
+
+ /**
+ * 打印请求情况 print(request, handler);
+ *
+ * @param request
+ */
+ public static String print (HttpServletRequest request, HandlerMethod handler) {
+ // 打印请求情况
+ String reqInfo = printForHandler(handler);
+ reqInfo += printForRequest(request);
+ logger.info("\n" + reqInfo);
+ return reqInfo;
+ }
+
+ /**
+ * 打印请求情况 print(request);
+ *
+ * @param request
+ */
+ public static String print (HttpServletRequest request) {
+ // 打印请求情况
+ String reqInfo = printForRequest(request);
+ logger.info("\n" + reqInfo);
+ return reqInfo;
+ }
+
+ private static String printForHandler (HandlerMethod handler) {
+ if (handler == null) {
+ return "";
+ }
+ StringBuilder handlerInfo = new StringBuilder("\n控制器类:" + handler.getBeanType().getName() + "." + handler.getMethod().getName() + "(" + handler.getBeanType().getSimpleName() + ".java:1)");
+ handlerInfo.append("\n页面URL类方法名:" + handler.getMethod().getName());
+ return handlerInfo.toString();
+ }
+
+
+ private static String printForRequest (HttpServletRequest request) {
+ StringBuilder reqInfo = new StringBuilder("\n完整请求:" + getFullUrl(request));
+ reqInfo.append("\n请求 方式:" + request.getMethod() + " " + (isAjaxRequest(request) ? "Ajax请求" : "常规请求"));
+ reqInfo.append("\n请求 URL:" + request.getRequestURI());
+ String paramsTxt = "\n请求参数:[ ";
+ int i = 0;
+ for (String key : request.getParameterMap().keySet()) {
+ String value = reqGetParam(request, key);
+ if (i++ == 0) {
+ paramsTxt += key + "=" + value;
+ } else {
+ paramsTxt += " | " + key + "=" + value;
+ }
+ }
+ reqInfo.append(paramsTxt + " ]");
+ reqInfo.append("\n\n ================ 请求参数信息结束 ================ ");
+ return reqInfo.toString();
+ }
+
+ /**
+ * @return String 返回类型
+ * @throws
+ * @Description: 超过指定长度,自动省略
+ */
+ private static String reqGetParam (HttpServletRequest req, String key) {
+ String val = req.getParameter(key);
+ int maxLength = 128;//允许显示最大长度
+ if (val != null && val.length() > maxLength) {
+ return val.substring(0, maxLength) + "...";
+ }
+ return val;
+ }
+
+ /**
+ * 得到一个完整URL(包含参数)
+ *
+ * @param request
+ * @return
+ */
+ public static String getFullUrl (HttpServletRequest request) {
+ StringBuilder url = new StringBuilder();
+ int i = 0;
+ url.append(request.getRequestURL());
+ for (String key : request.getParameterMap().keySet()) {
+ if (i++ == 0) {
+ url.append("?" + key + "=" + reqGetParam(request, key));
+ } else {
+ url.append("&" + key + "=" + reqGetParam(request, key));
+ }
+ }
+ return url.toString();
+ }
+
+ /**
+ * 得到一个请求的所有参数信息,参数值长度超过200则截断
+ *
+ * @param request
+ * @return
+ */
+ public static String getUrlAllparams (HttpServletRequest request) {
+ StringBuilder url = new StringBuilder();
+ String value;
+ for (String key : request.getParameterMap().keySet()) {
+ value = request.getParameter(key);
+ if (StringUtils.isNotEmpty(value) && value.length() > 200) {
+ value = value.substring(0, 200) + "...";
+ }
+ url.append(key + "=" + value + "&");
+ }
+ return url.toString();
+ }
+
+ /**
+ * isAjaxRequest:判断请求是否为Ajax请求.
+ *
+ * @param request 请求对象
+ * @return boolean
+ */
+ private static boolean isAjaxRequest (HttpServletRequest request) {
+ String header = request.getHeader("X-Requested-With");
+ boolean isAjax = "XMLHttpRequest".equals(header) ? true : false;
+ return isAjax;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/common/util/PropUtils.java b/src/main/java/org/svnadmin/common/util/PropUtils.java
new file mode 100644
index 0000000..722b933
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/util/PropUtils.java
@@ -0,0 +1,38 @@
+package org.svnadmin.common.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * @ClassName: PropUtils
+ * @Description: 常用配置文件操作
+ * @author hpboys
+ * @date 2015年7月8日 下午5:12:38
+ * @version V1.0
+ */
+public class PropUtils {
+
+ private static Map properties = new HashMap();
+
+ public static void initConfigProperties(Properties props) {
+ for (Object key : props.keySet()) {
+ String keyTemp = String.valueOf(key);
+ String valueTemp = props.getProperty(keyTemp);
+ properties.put(keyTemp, valueTemp);
+ }
+ }
+
+ public static Map getProperties() {
+ return properties;
+ }
+
+ public static String getProperty(String key) {
+ return properties.get(key);
+ }
+
+ public static String get(String key) {
+ return properties.get(key);
+ }
+}
diff --git a/src/main/java/org/svnadmin/common/util/SpringUtils.java b/src/main/java/org/svnadmin/common/util/SpringUtils.java
new file mode 100644
index 0000000..c7487e8
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/util/SpringUtils.java
@@ -0,0 +1,79 @@
+package org.svnadmin.common.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * Spring 工具类
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ */
+public class SpringUtils implements ApplicationContextAware {
+
+ /**
+ * 日志
+ */
+ private final Log LOG = LogFactory.getLog(SpringUtils.class);
+
+ /**
+ * ApplicationContext
+ */
+ private static ApplicationContext applicationContext;
+
+ /**
+ * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) {
+ LOG.info("Version: "+getVersion());
+ SpringUtils.applicationContext = applicationContext;
+ }
+
+ /**
+ * @return 取得存储在静态变量中的ApplicationContext.
+ */
+ public static ApplicationContext getApplicationContext() {
+ checkApplicationContext();
+ return applicationContext;
+ }
+
+ /**
+ * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ *
+ * @param name
+ * Bean的名称
+ * @return 对象
+ */
+ @SuppressWarnings("unchecked")
+ public static T getBean(String name) {
+ checkApplicationContext();
+ return (T) applicationContext.getBean(name);
+ }
+
+ /**
+ * 清除applicationContext静态变量.
+ */
+ public static void cleanApplicationContext() {
+ applicationContext = null;
+ }
+
+ /**
+ * 检查是否applicaitonContext未注入
+ */
+ private static void checkApplicationContext() {
+ if (applicationContext == null) {
+ throw new IllegalStateException(
+ "applicaitonContext未注入,请在applicationContext.xml中定义SpringUtils");
+ }
+ }
+
+ /**
+ * @return 当前的版本
+ * @since 3.0.2
+ */
+ public static String getVersion(){
+ return PropUtils.get("setting.version");
+ }
+}
diff --git a/src/main/java/org/svnadmin/common/web/BaseController.java b/src/main/java/org/svnadmin/common/web/BaseController.java
new file mode 100644
index 0000000..ec6e2f4
--- /dev/null
+++ b/src/main/java/org/svnadmin/common/web/BaseController.java
@@ -0,0 +1,111 @@
+package org.svnadmin.common.web;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.svnadmin.common.entity.PushMsg;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.util.PrintUtils;
+
+/**
+ * 基础控制器
+ * @author Zoro
+ * @datetime 2016/2/24 20:53
+ * @since 1.0.0
+ */
+public class BaseController {
+
+ protected Logger logger = Logger.getLogger(BaseController.class);
+
+ /**
+ * 全局异常控制,记录日志
+ * @param ex
+ * @param request
+ * @return
+ */
+ @ExceptionHandler(Throwable.class)
+ public String operateException(RuntimeException ex,HttpServletRequest request,HttpServletResponse rp) throws Exception{
+ PrintUtils.print(request);
+ logger.error(ex.getMessage(),ex);
+ logger.info("************* ------ 异常信息已记录 ------- ***********");
+ if(HttpUtils.isAjaxRequest(request)){
+ rp.getWriter().print("{\"info\":\"抱歉,操作失败,请稍后重试!\",\"status\":false}");
+ return "";
+ }else{
+ request.setAttribute("errorTips", ex.getMessage());
+ return "common/exception";//需各端添加此文件
+ }
+ }
+
+ /**
+ * 推送消息到客户端
+ * @param status
+ * @return
+ */
+ public static PushMsg pushMsg(Boolean status){
+ PushMsg pushMsg = new PushMsg();
+ pushMsg.setArg1(0);//默认值
+ pushMsg.setInfo(status? "恭喜,操作成功":"抱歉,操作失败!");
+ pushMsg.setStatus(status);
+ return pushMsg;
+ }
+
+ /**
+ * 推送消息到客户端
+ * @param info
+ * @param status
+ * @return
+ */
+ public static PushMsg pushMsg(Object info,Boolean status){
+ PushMsg pushMsg = new PushMsg();
+ pushMsg.setArg1(0);//默认值
+ pushMsg.setInfo(info);
+ pushMsg.setStatus(status);
+ return pushMsg;
+ }
+
+ /**
+ * 推送消息到客户端
+ * @param info
+ * @param status
+ * @param entrys 附加属性值,Key:Value
+ * @return
+ */
+ public static PushMsg pushMsg(Object info, Boolean status, Object... entrys){
+ PushMsg pushMsg = new PushMsg();
+ pushMsg.setArg1(0);//默认值
+ pushMsg.setInfo(info);
+ pushMsg.setStatus(status);
+ for (int i = 0; i < entrys.length; i+=2) {
+ pushMsg.getAttr().put(String.valueOf(entrys[i]), entrys[i+1]);
+ }
+ return pushMsg;
+ }
+
+ /**
+ * 推送消息到客户端
+ * @param info
+ * @param status
+ * @return
+ */
+ public static PushMsg pushMsg(Object info,Boolean status,int arg1){
+ PushMsg pushMsg = new PushMsg();
+ pushMsg.setArg1(arg1);//自定义值
+ pushMsg.setInfo(info);
+ pushMsg.setStatus(status);
+ return pushMsg;
+ }
+
+ /**
+ * 向指定Url进行重定向
+ * @param url
+ * @return
+ */
+ public String redirect(String url){
+ return "redirect:"+url;
+ }
+
+
+}
diff --git a/src/main/java/org/svnadmin/constant/Constants.java b/src/main/java/org/svnadmin/constant/Constants.java
new file mode 100644
index 0000000..46d2b30
--- /dev/null
+++ b/src/main/java/org/svnadmin/constant/Constants.java
@@ -0,0 +1,53 @@
+package org.svnadmin.constant;
+
+/**
+ * 常量
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ */
+public class Constants {
+ /**
+ * lang 保存在session中得key
+ */
+ public static final String SESSION_KEY_LANG = "_session_key_lang_";
+ /**
+ * 用户在session中key
+ */
+ public static final String SESSION_KEY_USER = "_session_key_user_";
+
+ /**
+ *
+ */
+ public static final String ERROR = "error";
+
+ /**
+ * svn协议
+ */
+ public static final String SVN = "svn";
+ /**
+ * http单库
+ */
+ public static final String HTTP = "http";
+ /**
+ * http多库
+ */
+ public static final String HTTP_MUTIL = "http-mutil";
+
+ /**
+ * 管理组
+ */
+ public static final String GROUP_MANAGER = "manager";
+
+ /**
+ * 项目默认的组
+ */
+ public static final String[] GROUPS = { GROUP_MANAGER, "developer",
+ "tester" };
+
+ /**
+ * 管理员角色代码
+ */
+ public static final String USR_ROLE_ADMIN = "admin";
+
+}
diff --git a/src/main/java/org/svnadmin/constant/SessionConstant.java b/src/main/java/org/svnadmin/constant/SessionConstant.java
new file mode 100644
index 0000000..d7d87d4
--- /dev/null
+++ b/src/main/java/org/svnadmin/constant/SessionConstant.java
@@ -0,0 +1,32 @@
+package org.svnadmin.constant;
+
+
+/**
+ * 会话键常量类.
+ * @author Zoro
+ * @datetime 2016/4/6 13:27
+ * @since 1.0.0
+ */
+public class SessionConstant {
+
+ /**
+ * 后台登录用户的session键名.
+ */
+ public static final String USER_SESSION_KEY = "adminUser";
+
+ /**
+ * 商户主帐号ID的session键名.
+ */
+ public static final String MAIN_USER_ID_SESSION_KEY = "pmsMainUserId";
+
+ /**
+ * 登录用户拥有的权限集合的session键名.
+ */
+ public static final String ACTIONS_SESSION_KEY = "actions";
+
+ /**
+ * 用户密码连续输错次数限制(默认5).
+ */
+ public static int WEB_PWD_INPUT_ERROR_LIMIT = 5;
+
+}
diff --git a/src/main/java/org/svnadmin/controller/basic/ConsoleController.java b/src/main/java/org/svnadmin/controller/basic/ConsoleController.java
new file mode 100644
index 0000000..089da32
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/basic/ConsoleController.java
@@ -0,0 +1,47 @@
+package org.svnadmin.controller.basic;
+
+import javax.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.SessionUtils;
+
+/**
+ * 控制台控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class ConsoleController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+
+ /**
+ * 控制台主页
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "console", method = RequestMethod.GET)
+ public String console(HttpSession session, ModelMap map) {
+ boolean hasAdminRight = SessionUtils.hasAdminRight(session);
+ if(hasAdminRight){
+ //管理员登录可查看
+ return redirect("pjList");
+ }else{
+ //普通登录可查看
+ return redirect("usrRightListView");
+ }
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/controller/basic/LoginController.java b/src/main/java/org/svnadmin/controller/basic/LoginController.java
new file mode 100644
index 0000000..b7d80a3
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/basic/LoginController.java
@@ -0,0 +1,78 @@
+package org.svnadmin.controller.basic;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AuthPassport;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.constant.SessionConstant;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.I18N;
+
+/**
+ * @描述: 登录登出控制器.
+ * @作者: Zoro.
+ * @创建时间: 2016-05-08 12:52.
+ * @版本: 1.0.0.
+ */
+@Controller
+@RequestMapping("/")
+public class LoginController extends BaseController{
+
+ @Autowired
+ private UsrService usrService;
+
+ /**
+ * SVN后台管理员登录页面
+ */
+ @AuthPassport
+ @RequestMapping(value = "login", method = RequestMethod.GET)
+ public String login(HttpServletRequest request, ModelMap map){
+ map.put("lbe_usr_txt", I18N.getLbl(request, "usr.usr", "帐号"));
+ map.put("lbe_psw_txt", I18N.getLbl(request,"usr.psw","密码"));
+ map.put("btn_login_txt", I18N.getLbl(request,"login.btn.login","登录"));
+ return "basic/login";
+ }
+
+ /**
+ * 登录处理
+ */
+ @AuthPassport
+ @RequestMapping(value = "loginHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object loginHandler(HttpServletRequest request,
+ @RequestParam("usr")String usr,
+ @RequestParam("psw")String psw){
+ Usr loginUser = null;
+ //登录
+ try {
+ loginUser = usrService.login(usr, psw);
+ if (null == loginUser) {
+ return pushMsg("用户名或密码错误!", false);
+ }
+ }catch (Exception ex){
+ return pushMsg(ex.getMessage(), false);
+ }
+ request.getSession().setAttribute(SessionConstant.USER_SESSION_KEY, loginUser);
+ return pushMsg("认证通过", true , "url" , "console");
+ }
+
+ /**
+ * 登录退出处理
+ */
+ @RequestMapping(value = "logout", method = RequestMethod.GET)
+ public String logout(HttpServletRequest request, ModelMap map){
+ request.getSession().removeAttribute(SessionConstant.USER_SESSION_KEY);
+ return redirect("login");
+ }
+
+
+
+}
diff --git a/src/main/java/org/svnadmin/controller/rep/RepController.java b/src/main/java/org/svnadmin/controller/rep/RepController.java
new file mode 100644
index 0000000..cfd4572
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/rep/RepController.java
@@ -0,0 +1,162 @@
+package org.svnadmin.controller.rep;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.Ajax;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+import org.svnadmin.service.DefaultTreeService;
+import org.svnadmin.service.PjAuthService;
+import org.svnadmin.service.PjGrService;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.RepositoryService;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.SessionUtils;
+import org.svnadmin.util.UsrProvider;
+
+/**
+ * SVN项目资源权限控制器
+ * @author Zoro
+ * @datetime 2016/5/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class RepController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+ @Autowired
+ private PjGrService pjGrService;
+ @Autowired
+ private PjAuthService pjAuthService;
+ /**
+ * 仓库服务层
+ */
+ @Autowired
+ private RepositoryService repositoryService;
+ @Autowired
+ private DefaultTreeService treeService;
+
+ /**
+ * 资源
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "repository", method = RequestMethod.GET)
+ public String repository(HttpSession session,
+ @RequestParam("pj")String _pj,ModelMap map) {
+ Pj pj = pjService.get(_pj);
+ map.put("pj",pj);
+ map.put("usrList", usrService.list());
+ map.put("pjgrlist", pjGrService.list(_pj));
+ map.put("pjreslist", pjAuthService.getResList(_pj));
+ return "rep/repository";
+ }
+
+ /**
+ * 项目资源树数据
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "repTree", method = RequestMethod.POST ,params = "action=data")
+ @ResponseBody
+ public Object repTree(HttpServletRequest request) {
+ //treeId treeParentId pj path
+ UsrProvider.setUsr(SessionUtils.getLogedUser(request.getSession()));
+ Map params = HttpUtils.getParamters(request);
+ Ajax ajax = treeService.execute(params);
+ return ajax.getResult();
+ }
+
+ /**
+ * 项目列表
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "repPathAuth", method = RequestMethod.GET ,params = "action=data")
+ @ResponseBody
+ public Object repPathAuth(HttpServletRequest request) {
+ Map params = HttpUtils.getParams(request);
+ String pj = params.get("pj");
+ String res = params.get("res");
+ if(StringUtils.isBlank(res)){
+ String path = params.get("path");//从rep 树点击进来,传递的是path
+ if(StringUtils.isNotBlank(path)){
+ res = this.pjAuthService.formatRes(pj, path);
+ }
+ }else{
+// res = entity.getRes();
+ }
+// entity.setRes(res);
+ List list = pjAuthService.list(pj,res);
+ PageBean pageBean = new PageBean<>();
+ pageBean.setDataList(list);
+ pageBean.setRecordCount(list.size());
+ return pageBean;
+ }
+
+ /**
+ * 处理资源权限(添加)
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "repPathAuthAddHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjCreateHandler(HttpServletRequest request) {
+ Map params = HttpUtils.getParams(request);
+ String pj = params.get("pj");
+ String res = params.get("res");
+
+ String[] grs = StringUtils.isEmpty(params.get("grs"))? null:params.get("grs").split(",");
+ String[] usrs = StringUtils.isEmpty(params.get("usrs"))? null:params.get("usrs").split(",");
+
+ String rw = params.get("rw");
+ PjAuth entity = new PjAuth();
+ entity.setPj(pj);
+ entity.setRes(res);
+ request.setAttribute("entity", entity);
+ pjAuthService.save(pj, res, rw, grs, usrs);
+ return pushMsg("操作资源权限成功", true);
+ }
+
+ /**
+ * 处理资源权限(移除)
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "repPathAuthRemoveHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object repPathAuthRemoveHandler(HttpServletRequest request) {
+ Map params = HttpUtils.getParams(request);
+ String pj = params.get("pj");
+ String gr = params.get("gr");
+ String usr = params.get("usr");
+ String res = params.get("res");
+
+ if (StringUtils.isNotBlank(gr)) {
+ pjAuthService.deleteByGr(pj, gr, res);
+ } else if (StringUtils.isNotBlank(usr)) {
+ pjAuthService.deleteByUsr(pj, usr, res);
+ }
+ return pushMsg("操作资源权限成功", true);
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/controller/svn/ProjectController.java b/src/main/java/org/svnadmin/controller/svn/ProjectController.java
new file mode 100644
index 0000000..5c17377
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/svn/ProjectController.java
@@ -0,0 +1,115 @@
+package org.svnadmin.controller.svn;
+
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.SessionUtils;
+
+/**
+ * SVN项目管理控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class ProjectController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+
+ /**
+ * 项目列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjList", method = RequestMethod.GET)
+ public String pjList(HttpSession session, ModelMap map) {
+ boolean hasAdminRight = SessionUtils.hasAdminRight(session);
+ List list = null;
+ if (hasAdminRight) {
+ list = pjService.list();// 所有项目
+ }
+ else {
+ list = pjService.list(SessionUtils.getLogedUser(session).getUsr());// 登录用户可以看到的项目
+ }
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(list.size());
+ pageBean.setDataList(list);
+ map.put("pageBean", pageBean);
+ return "svn/pj_list";
+ }
+
+ /**
+ * 项目列表数据
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjList", method = RequestMethod.GET ,params = "action=data")
+ @ResponseBody
+ public Object pjListDataSet(HttpSession session,@RequestParam("pageNumber")int pageNumber) {
+ PageBean pageBean = new PageBean(pageNumber,10);
+// usrService.queryForPageBean(pageBean);
+ return pageBean;
+ }
+
+ /**
+ * 创建项目
+ * @param session
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjCreate", method = RequestMethod.GET)
+ public String pjCreate(HttpSession session, ModelMap map) {
+ return "svn/pj_create";
+ }
+
+ /**
+ * 创建项目处理
+ * @param session
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjCreateHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjCreateHandler(HttpSession session,Pj entity) {
+ try {
+ pjService.save(entity);
+ return pushMsg("创建项目成功", true , "url" , "pjList");
+ }catch (Exception e){
+ logger.error("创建项目提交失败",e);
+ return pushMsg("创建项目失败,"+e.getMessage(), true);
+ }
+ }
+
+ @AdminAuthPassport
+ @RequestMapping(value = "pjDelete", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjDelete(HttpSession session, @RequestParam("pj")String pj, ModelMap map) {
+ try {
+ pjService.delete(pj);
+ return pushMsg("项目删除成功", true , "url" , "pjList");
+ }catch (Exception e){
+ logger.error("项目删除失败",e);
+ return pushMsg("项目删除失败," + e.getMessage(), true);
+ }
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/controller/svn/ProjectGrController.java b/src/main/java/org/svnadmin/controller/svn/ProjectGrController.java
new file mode 100644
index 0000000..fb3a6ca
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/svn/ProjectGrController.java
@@ -0,0 +1,92 @@
+package org.svnadmin.controller.svn;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.PjGr;
+import org.svnadmin.service.PjGrService;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.UsrService;
+
+/**
+ * SVN项目用户组管理控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class ProjectGrController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+ @Autowired
+ private PjGrService pjGrService;
+
+ /**
+ * 项目用户组列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjGrList", method = RequestMethod.GET)
+ public String pjGrList(HttpSession session,@RequestParam("pj")String pj, ModelMap map) {
+ map.put("pj", pjService.get(pj));
+ return "svn/pj_gr_list";
+ }
+
+ /**
+ * 项目用户组列表(数据集)
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjGrList", method = RequestMethod.GET, params = "action=data")
+ @ResponseBody
+ public Object pjGrList(HttpSession session,@RequestParam("pj")String pj) {
+ // 项目账户
+ List list = pjGrService.list(pj);
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(list.size());
+ pageBean.setDataList(list);
+ return pageBean;
+ }
+
+ /**
+ * 添加项目用户组处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjGrAddHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjGrAddHandler(HttpServletRequest request,PjGr entity) {
+ pjGrService.save(entity);
+ return pushMsg("添加项目用户组成功", true);
+ }
+
+ /**
+ * 删除项目用户组处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjGrRemoveHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjGrRemoveHandler(HttpServletRequest request,PjGr entity) {
+ pjGrService.delete(entity.getPj(), entity.getGr());
+ return pushMsg("删除项目用户组成功", true);
+ }
+}
diff --git a/src/main/java/org/svnadmin/controller/svn/ProjectGrUsrController.java b/src/main/java/org/svnadmin/controller/svn/ProjectGrUsrController.java
new file mode 100644
index 0000000..c42d324
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/svn/ProjectGrUsrController.java
@@ -0,0 +1,113 @@
+package org.svnadmin.controller.svn;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.PjGrUsr;
+import org.svnadmin.service.PjGrUsrService;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.PjUsrService;
+import org.svnadmin.service.UsrService;
+
+/**
+ * SVN项目用户组管理控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class ProjectGrUsrController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+ @Autowired
+ private PjUsrService pjUsrService;
+ @Autowired
+ private PjGrUsrService pjGrUsrService;
+
+ /**
+ * 项目组用户列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjGrUsrList", method = RequestMethod.GET)
+ public String pjGrUsrList(HttpSession session,
+ @RequestParam("pj")String pj,
+ @RequestParam("gr")String gr,ModelMap map) {
+ // 账户
+ map.put("pj", pj);
+ map.put("gr", gr);
+ map.put("usrList", usrService.listUnSelected(pj, gr));
+ return "svn/pj_gr_usr_list";
+ }
+
+ /**
+ * 项目组用户列表(数据集)
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjGrUsrList", method = RequestMethod.GET, params = "action=data")
+ @ResponseBody
+ public Object pjGrUsrList(HttpSession session,
+ @RequestParam("pj")String pj,
+ @RequestParam("gr")String gr) {
+ //组用户账户
+ List list = pjGrUsrService.list(pj, gr);
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(list.size());
+ pageBean.setDataList(list);
+ return pageBean;
+ }
+
+ /**
+ * 添加项目组用户处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjGrUsrAddHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjGrUsrAddHandler(HttpServletRequest request) {
+ Map params = HttpUtils.getParams(request);
+ String pj = params.get("pj");
+ String gr = params.get("gr");
+ String[] usrs = StringUtils.isEmpty(params.get("usrs"))? null:params.get("usrs").split(",");
+ this.pjGrUsrService.save(pj, gr, usrs);
+ return pushMsg("添加项目组用户成功", true);
+ }
+
+ /**
+ * 删除项目组用户处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjGrUsrRemoveHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjGrUsrRemoveHandler(HttpServletRequest request) {
+ Map params = HttpUtils.getParams(request);
+ String pj = params.get("pj");
+ String gr = params.get("gr");
+ String usr = params.get("usr");
+ this.pjGrUsrService.delete(pj, gr, usr);
+ return pushMsg("删除项目组用户成功", true);
+ }
+}
diff --git a/src/main/java/org/svnadmin/controller/svn/ProjectUsrController.java b/src/main/java/org/svnadmin/controller/svn/ProjectUsrController.java
new file mode 100644
index 0000000..d85fe9c
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/svn/ProjectUsrController.java
@@ -0,0 +1,111 @@
+package org.svnadmin.controller.svn;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.PjUsr;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.PjUsrService;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.EncryptUtil;
+
+/**
+ * SVN项目用户管理控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class ProjectUsrController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+ @Autowired
+ private PjUsrService pjUsrService;
+
+ /**
+ * 项目用户列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjUsrList", method = RequestMethod.GET)
+ public String pjUsrList(HttpSession session,@RequestParam("pj")String pj, ModelMap map) {
+ // 账户
+ List usrList = usrService.list(pj);
+ map.put("pj", pjService.get(pj));
+ map.put("usrList", usrList);
+ return "svn/pj_usr_list";
+ }
+
+ /**
+ * 项目用户列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "pjUsrList", method = RequestMethod.GET, params = "action=data")
+ @ResponseBody
+ public Object pjUsrList(HttpSession session,@RequestParam("pj")String pj) {
+ // 项目账户
+ List list = pjUsrService.list(pj);
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(list.size());
+ pageBean.setDataList(list);
+ return pageBean;
+ }
+
+ /**
+ * 添加项目用户处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjUsrAddHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjUsrAddHandler(HttpServletRequest request,PjUsr entity) {
+ Map params = HttpUtils.getParams(request);
+ if ("1".equals(params.get("defaultPswd"))) {
+ entity.setPsw(usrService.get(entity.getUsr()).getPsw());
+ } else {
+ entity.setPsw(EncryptUtil.encrypt(entity.getPsw()));
+ }
+ pjUsrService.save(entity);
+ return pushMsg("添加项目用户成功", true);
+ }
+
+ /**
+ * 删除项目用户处理
+ * @param request
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "pjUsrRemoveHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjUsrRemoveHandler(HttpServletRequest request,PjUsr entity) {
+ Map params = HttpUtils.getParams(request);
+ if ("1".equals(params.get("defaultPswd"))) {
+ entity.setPsw(usrService.get(entity.getUsr()).getPsw());
+ } else {
+ entity.setPsw(EncryptUtil.encrypt(entity.getPsw()));
+ }
+ pjUsrService.save(entity);
+ return pushMsg("添加项目用户成功", true);
+ }
+}
diff --git a/src/main/java/org/svnadmin/controller/usr/UsrController.java b/src/main/java/org/svnadmin/controller/usr/UsrController.java
new file mode 100644
index 0000000..74a1e5e
--- /dev/null
+++ b/src/main/java/org/svnadmin/controller/usr/UsrController.java
@@ -0,0 +1,188 @@
+package org.svnadmin.controller.usr;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.web.BaseController;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+import org.svnadmin.entity.PjUsr;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.service.PjService;
+import org.svnadmin.service.PjUsrService;
+import org.svnadmin.service.UsrService;
+import org.svnadmin.util.EncryptUtil;
+import org.svnadmin.util.SessionUtils;
+
+/**
+ * SVN用户管理控制器
+ * @author Zoro
+ * @datetime 2016/1/20 19:48
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class UsrController extends BaseController {
+
+ @Autowired
+ private UsrService usrService;
+ @Autowired
+ private PjService pjService;
+ @Autowired
+ private PjUsrService pjUsrService;
+
+ /**
+ * 用户列表
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "usrList", method = RequestMethod.GET)
+ public String usrList(HttpSession session, ModelMap map) {
+ return "usr/usr_list";
+ }
+
+ /**
+ * 用户列表数据
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "usrList", method = RequestMethod.GET ,params = "action=data")
+ @ResponseBody
+ public Object usrListDataSet(HttpSession session) {
+ List list = usrService.list();
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(list.size());
+ pageBean.setDataList(list);
+ return pageBean;
+ }
+
+ /**
+ * 创建用户处理
+ * @param session
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "usrCreateHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object usrCreateHandler(HttpSession session,Usr entity) {
+ try {
+ entity.setPsw(EncryptUtil.encrypt(entity.getPsw()));
+ usrService.save(entity);
+ return pushMsg("创建用户成功", true , "url" , "usrList");
+ }catch (Exception e){
+ logger.error("创建用户提交失败",e);
+ return pushMsg("创建用户失败,"+e.getMessage(), true);
+ }
+ }
+
+ /**
+ * 删除用户处理
+ * @param session
+ * @return
+ */
+ @AdminAuthPassport
+ @RequestMapping(value = "usrRemoveHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object usrRemoveHandler(HttpSession session,String usr) {
+ if(!SessionUtils.hasAdminRight(session)){
+ return pushMsg("你没有权限删除用户!", false);
+ }
+ if (SessionUtils.getLogedUser(session).getUsr().equals(usr)) {// 当前用户
+ return pushMsg("不能删除自己!", false);
+ }
+ usrService.delete(usr);
+ return pushMsg(true);
+ }
+
+ /**
+ * 查看用户权限
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "usrRightList", method = RequestMethod.GET, params = "action=data")
+ @ResponseBody
+ public Object usrRightListDataSet(HttpSession session,String usr) {
+ //查看用户权限
+ if(StringUtils.isBlank(usr)){
+ usr = SessionUtils.getLogedUser(session).getUsr();
+ }
+ List auths = this.usrService.getAuths(usr);
+ PageBean pageBean = new PageBean();
+ pageBean.setRecordCount(auths.size());
+ pageBean.setDataList(auths);
+ return pageBean;
+ }
+
+
+ /**
+ * 查看用户权限
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "usrRightListView", method = RequestMethod.GET)
+ public String usrRightListDataSet(HttpSession session) {
+ //查看用户权限
+ return "usr/usr_auth";
+ }
+
+ /**
+ * 用户更改密码
+ * @param session
+ * @return
+ */
+ @RequestMapping(value = "updatePswd", method = RequestMethod.GET)
+ public String updatePswd(HttpSession session, ModelMap map) {
+ return "usr/usr_update_pswd";
+ }
+
+ /**
+ * 用户更改密码处理
+ * @param request
+ * @return
+ */
+ @RequestMapping(value = "usrUpdatePswdHandler", method = RequestMethod.POST)
+ @ResponseBody
+ public Object pjUsrAddHandler(HttpServletRequest request) {
+ Usr usr = SessionUtils.getLogedUser(request.getSession());
+ Map params = HttpUtils.getParams(request);
+ //验证老密码和新密码
+ String oldPsw = params.get("oldPsw");
+ if(usr.getPsw().equals(EncryptUtil.encrypt(oldPsw))){
+ //验证老密码通过
+ //验证老密码和新密码是否一致
+ String newPsw = params.get("newPsw");
+ if(usr.getPsw().equals(EncryptUtil.encrypt(newPsw))){
+ return pushMsg("新密码不能和老密码保持一致", false);
+ }
+ //更新用户登录密码
+ usr.setPsw(EncryptUtil.encrypt(newPsw));
+ usrService.save(usr);
+ //更新用户项目认证密码
+ List pjList = usrService.getPjList(usr.getUsr());
+ for (Pj pj : pjList) {
+ PjUsr pjUsr = new PjUsr();
+ pjUsr.setUsr(usr.getUsr());
+ pjUsr.setPj(pj.getPj());
+ pjUsr.setPsw(EncryptUtil.encrypt(newPsw));
+ pjUsrService.save(pjUsr);
+ }
+ return pushMsg("用户项目认证密码修改成功", true);
+ }else{
+ return pushMsg("您输入的老密码有误", false);
+ }
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/dao/Dao.java b/src/main/java/org/svnadmin/dao/Dao.java
new file mode 100644
index 0000000..02dc650
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/Dao.java
@@ -0,0 +1,99 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+
+/**
+ * 所有DAO的父类
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+public class Dao {
+
+ /**
+ * 日志
+ */
+ private final Log LOG = LogFactory.getLog(Dao.class);
+
+ /**
+ * 数据源
+ */
+ @Resource(name = "dataSource")
+ DataSource dataSource;
+
+ /**
+ * @return 数据源
+ */
+ protected DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * @return 数据库连接
+ */
+ protected Connection getConnection() {
+ return DataSourceUtils.getConnection(getDataSource());
+ }
+ /**
+ * 验证是否可以连接上数据库 see Issue 12
+ *
+ * @throws SQLException jdbc异常
+ */
+ public void validatConnection() throws SQLException {
+ Connection conn = null;
+ try {
+ conn = this.getConnection();
+ } finally {
+ this.close(null, null, conn);
+ }
+ }
+ /**
+ * 关闭资源
+ *
+ * @param rs
+ * ResultSet
+ * @param s
+ * Statement
+ * @param conn
+ * 数据库连接
+ */
+ protected void close(ResultSet rs, Statement s, Connection conn) {
+ // rs
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ LOG.error(e.getMessage());
+ }
+ }
+ // s
+ if (s != null) {
+ try {
+ s.close();
+ } catch (SQLException e) {
+ LOG.error(e.getMessage());
+ }
+ }
+ // conn
+ if (conn != null) {
+ try {
+ // conn.close();
+ DataSourceUtils.releaseConnection(conn, getDataSource());
+ } catch (Exception e) {
+ LOG.error(e.getMessage());
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/I18nDao.java b/src/main/java/org/svnadmin/dao/I18nDao.java
new file mode 100644
index 0000000..0dffee2
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/I18nDao.java
@@ -0,0 +1,268 @@
+/**
+ *
+ */
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Repository;
+import org.svnadmin.entity.I18n;
+
+/**
+ * 语言DAO
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ */
+@Repository(I18nDao.BEAN_NAME)
+public class I18nDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME="i18nDao";
+
+ /**
+ *
+ * @param lang 语言
+ * @param id 键值
+ * @return 多语言
+ */
+ public I18n get(String lang,String id) {
+ String sql = "select lang,id,lbl from i18n where lang=? and id=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, lang);
+ pstmt.setString(index++, id);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readI18n(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return 多语言列表
+ */
+ public List getList() {
+ String sql = "select lang,id,lbl from i18n order by lang,id";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ List results = new ArrayList();
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ results.add(readI18n(rs));
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return results;
+ }
+ /**
+ * @param id 键值
+ * @return 相同键值的语言列表
+ */
+ public Map getI18ns(String id) {
+ String sql = "select lang,id,lbl from i18n where id=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ Map results = new HashMap();
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, id);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ I18n i18n = readI18n(rs);
+ results.put(i18n.getLang(),i18n);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return results;
+ }
+ /**
+ * 从ResultSet中读取i18n对象
+ *
+ * @param rs
+ * ResultSet
+ * @return i18n对象
+ * @throws SQLException
+ * JDBC异常
+ */
+ I18n readI18n(ResultSet rs) throws SQLException {
+ I18n result = new I18n();
+ result.setLang(rs.getString("lang"));
+ result.setId(rs.getString("id"));
+ result.setLbl(rs.getString("lbl"));
+ return result;
+ }
+
+ /**
+ * 更新
+ *
+ * @param i18n 多语言
+ *
+ * @return 更新数量
+ */
+ public int update(I18n i18n) {
+ String sql = "update i18n set lbl=? where lang=? and id=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, i18n.getLbl());
+ pstmt.setString(index++, i18n.getLang());
+ pstmt.setString(index++, i18n.getId());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 增加
+ *
+ * @param i18n 多语言
+ *
+ * @return 更新数量
+ */
+ public int insert(I18n i18n) {
+ String sql = "insert into i18n (lang,id,lbl) values (?,?,?)";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, i18n.getLang());
+ pstmt.setString(index++, i18n.getId());
+ pstmt.setString(index++, i18n.getLbl());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+ /**
+ * 是否存在这种语言
+ * @param lang 语言
+ * @return true表示数据库存在这个语言,否则返回false
+ */
+ public boolean existsLang(String lang) {
+ String sql = "select count(1) from i18n where lang=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ pstmt.setString(1, lang);
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return rs.getInt(1)>0;
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return false;
+ }
+ /**
+ * @return 获取系统现有的语言
+ */
+ public List getLangs() {
+ String sql = "select distinct lang from i18n order by lang";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ List results = new ArrayList();
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ results.add(rs.getString("lang"));
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return results;
+ }
+ /**
+ * @return 键值列表
+ */
+ public List getIds() {
+ String sql = "select id,count(id) total from i18n group by id order by id";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ List results = new ArrayList();
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ I18n i18n = new I18n();
+ i18n.setId(rs.getString("id"));
+ i18n.setTotal(rs.getInt("total"));
+ results.add(i18n);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return results;
+ }
+}
diff --git a/src/main/java/org/svnadmin/dao/PjAuthDao.java b/src/main/java/org/svnadmin/dao/PjAuthDao.java
new file mode 100644
index 0000000..41d40a0
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/PjAuthDao.java
@@ -0,0 +1,585 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Repository;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.entity.PjAuth;
+
+/**
+ * 项目资源的权限DAO
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Repository(PjAuthDao.BEAN_NAME)
+public class PjAuthDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjAuthDao";
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param res
+ * 资源
+ * @return 项目组资源的权限
+ */
+ public PjAuth getByGr(String pj, String gr, String res) {
+ String sql = "select pj,res,rw,gr,' ' usr,' ' usrname from pj_gr_auth where pj = ? and gr=? and res=? ";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+ pstmt.setString(index++, res);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPjAuth(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ * @param res
+ * 资源
+ * @return 项目用户资源的权限
+ */
+ public PjAuth getByUsr(String pj, String usr, String res) {
+ String sql = "select a.pj,a.res,a.rw,b.usr,b.name as usrname,' ' gr from pj_usr_auth a left join usr b on (a.usr=b.usr) where a.pj = ? and a.usr=? and a.res=? ";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, usr);
+ pstmt.setString(index++, res);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPjAuth(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+ /**
+ * @param usr
+ * 用户
+ * @return 用户的权限
+ */
+ public List getByUsr(String usr) {
+ String sql = "select b.pj,p.des,b.usr,b.res,b.rw from usr a";
+ sql+=" join pj_usr_auth b on (a.usr = b.usr)";
+ sql+=" join pj p on (b.pj=p.pj)";
+ sql+=" where a.usr=?";
+
+ sql+=" union all";
+
+ sql+=" select c.pj,p.des,a.usr,c.res,c.rw from usr a";
+ sql+=" join pj_gr_usr b on (a.usr = b.usr)";
+ sql+=" join pj_gr_auth c on (b.pj = c.pj and b.gr = c.gr)";
+ sql+=" join pj p on (b.pj=p.pj)";
+ sql+=" where a.usr=?";
+
+ sql+=" order by 1,4";//TODO 为了兼容sqlserver
+
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+ pstmt.setString(index++, usr);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+
+ PjAuth result = new PjAuth();
+ result.setPj(rs.getString("pj"));
+ result.setDes(rs.getString("des"));
+ result.setUsr(rs.getString("usr"));
+ result.setRes(rs.getString("res"));
+ String rw = rs.getString("rw");
+ if (StringUtils.isBlank(rw)) {
+ rw = "";
+ }
+ result.setRw(rw);
+
+ list.add(result);
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @param res 资源
+ * @return 项目资源的权限列表
+ */
+ public List getList(String pj,String res) {
+ String sql = "select pj,res,rw,gr,' ' usr,' ' usrname from pj_gr_auth where pj=? and res = ? "
+ + " UNION "
+ + " select a.pj,a.res,a.rw,' ' gr,a.usr,b.name as usrname from pj_usr_auth a left join usr b on (a.usr=b.usr) where a.pj=? and a.res = ? "
+ + " order by res,gr,usr";
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, res);
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, res);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjAuth(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+ /**
+ * @param pj
+ * 项目
+ * @return 项目资源的权限列表
+ */
+ public List getList(String pj) {
+ String sql = "select pj,res,rw,gr,' ' usr,' ' usrname from pj_gr_auth where pj=? "
+ + " UNION "
+ + " select a.pj,a.res,a.rw,' ' gr,a.usr,b.name as usrname from pj_usr_auth a left join usr b on (a.usr = b.usr) where a.pj=? "
+ + " order by res,gr,usr";
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjAuth(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rootPath
+ * svn root path
+ * @return 具有相同svn root的项目资源的权限列表
+ */
+ public List getListByRootPath(String rootPath) {
+ String sql = "select pj,res,rw,gr,' ' usr,' ' usrname from pj_gr_auth where pj in (select distinct pj from pj where type=? and path like ?) "
+ + " UNION "
+ + " select a.pj,a.res,a.rw,' ' gr,a.usr,b.name usrname from pj_usr_auth a left join usr b on (a.usr=b.usr) where a.pj in (select distinct pj from pj where type=? and path like ?) "
+ + " order by res,gr,usr";
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, Constants.HTTP_MUTIL);
+ pstmt.setString(index++, rootPath + "%");//TODO 大小写敏感?
+ pstmt.setString(index++, Constants.HTTP_MUTIL);
+ pstmt.setString(index++, rootPath + "%");//TODO 大小写敏感?
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjAuth(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rs
+ * ResultSet
+ * @return 项目资源的权限
+ * @throws SQLException
+ * jdbc异常
+ */
+ PjAuth readPjAuth(ResultSet rs) throws SQLException {
+ PjAuth result = new PjAuth();
+ result.setPj(rs.getString("pj"));
+ result.setGr(rs.getString("gr"));
+ result.setUsr(rs.getString("usr"));
+ result.setUsrName(rs.getString("usrname"));
+ result.setRes(rs.getString("res"));
+ String rw = rs.getString("rw");
+ if (StringUtils.isBlank(rw)) {
+ rw = "";
+ }
+ result.setRw(rw);
+
+ return result;
+ }
+
+ /**
+ * 删除项目 组资源的权限
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param res
+ * 资源
+ */
+ public void deleteByGr(String pj, String gr, String res) {
+ String sql = "delete from pj_gr_auth where pj = ? and gr=? and res=? ";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+ pstmt.setString(index++, res);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除项目用户资源的权限
+ *
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ * @param res
+ * 资源
+ */
+ public void deleteByUsr(String pj, String usr, String res) {
+ String sql = "delete from pj_usr_auth where pj = ? and usr=? and res=? ";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, usr);
+ pstmt.setString(index++, res);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除项目 资源的权限
+ *
+ * @param pj
+ * 项目
+ */
+ public void deletePj(String pj) {
+ // pj_gr_auth
+ String sql = "delete from pj_gr_auth where pj = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ // pj_usr_auth
+ sql = "delete from pj_usr_auth where pj = ?";
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除项目 组资源的权限
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ */
+ public void deletePjGr(String pj, String gr) {
+ String sql = "delete from pj_gr_auth where pj = ? and gr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除用户的项目资源的权限
+ *
+ * @param usr
+ * 用户
+ */
+ public void deleteUsr(String usr) {
+ String sql = "delete from pj_usr_auth where usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 保存项目组权限
+ *
+ * @param pjAuth
+ * 项目组权限
+ */
+ public void saveByGr(PjAuth pjAuth) {
+ if (this.getByGr(pjAuth.getPj(), pjAuth.getGr(), pjAuth.getRes()) == null) {
+ String sql = "insert into pj_gr_auth (pj,gr,res,rw) values (?,?,?,?)";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjAuth.getPj());
+ pstmt.setString(index++, pjAuth.getGr());
+ pstmt.setString(index++, pjAuth.getRes());
+ pstmt.setString(index++, pjAuth.getRw());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ } else {
+ String sql = "update pj_gr_auth set rw=? where pj=? and gr=? and res=?";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjAuth.getRw());
+ pstmt.setString(index++, pjAuth.getPj());
+ pstmt.setString(index++, pjAuth.getGr());
+ pstmt.setString(index++, pjAuth.getRes());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+ }
+
+ /**
+ * 保存项目用户权限
+ *
+ * @param pjAuth
+ * 项目用户权限
+ */
+ public void saveByUsr(PjAuth pjAuth) {
+ if (this.getByUsr(pjAuth.getPj(), pjAuth.getUsr(), pjAuth.getRes()) == null) {
+ String sql = "insert into pj_usr_auth (pj,usr,res,rw) values (?,?,?,?)";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjAuth.getPj());
+ pstmt.setString(index++, pjAuth.getUsr());
+ pstmt.setString(index++, pjAuth.getRes());
+ pstmt.setString(index++, pjAuth.getRw());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ } else {
+ String sql = "update pj_usr_auth set rw=? where pj=? and usr=? and res=?";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjAuth.getRw());
+ pstmt.setString(index++, pjAuth.getPj());
+ pstmt.setString(index++, pjAuth.getUsr());
+ pstmt.setString(index++, pjAuth.getRes());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目的资源列表
+ */
+ public List getResList(String pj) {
+ String sql = "select distinct res from pj_gr_auth where pj=? "
+ + " UNION select distinct res from pj_usr_auth where pj=? order by res";
+
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(rs.getString("res"));
+
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/PjDao.java b/src/main/java/org/svnadmin/dao/PjDao.java
new file mode 100644
index 0000000..3a81f68
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/PjDao.java
@@ -0,0 +1,267 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Repository;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.entity.Pj;
+
+/**
+ * 项目DAO
+ *
+ * @author Huiwu Yuan
+ *
+ */
+@Repository(PjDao.BEAN_NAME)
+public class PjDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjDao";
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目
+ */
+ public Pj get(String pj) {
+ String sql = "select pj,path,url,des,type from pj where pj = ?";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPj(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @return 项目列表
+ */
+ public List getList() {
+ String sql = "select pj,path,url,des,type from pj order by pj";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPj(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param usr
+ * 用户
+ * @return 用户有权限的项目列表(用户是否是这个项目的管理员)
+ */
+ public List getList(String usr) {
+ String sql = "select p.pj,p.path,p.url,p.des,p.type,pm.pj manager from ( "
+ + " select distinct a.pj,a.path,a.url,a.des,a.type from pj a where "
+ + " exists (select b.usr from pj_gr_usr b where a.pj=b.pj and b.usr=?) "
+ + " or exists(select c.usr from pj_usr_auth c where a.pj=c.pj and c.usr=?) "
+ + " ) p "
+ + " left join ( "
+ + " select distinct a.pj from pj a where "
+ // TODO like ? 应该是 = ? ,用like主要是兼容3.0版本 see: Issue 4
+ + " exists (select b.usr from pj_gr_usr b where a.pj=b.pj and b.usr=? and b.gr like ?)"
+ + " ) pm on p.pj=pm.pj";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+ pstmt.setString(index++, usr);
+ pstmt.setString(index++, usr);
+ // TODO 主要是兼容3.0版本
+ pstmt.setString(index++, "%" + Constants.GROUP_MANAGER);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ Pj pj = readPj(rs);
+ String manager = rs.getString("manager");// 是否是管理员组的用户
+ pj.setManager(StringUtils.isNotBlank(manager));
+ list.add(pj);
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rs
+ * ResultSet
+ * @return 项目
+ * @throws SQLException
+ * jdbc异常
+ */
+ public Pj readPj(ResultSet rs) throws SQLException {
+ Pj result = new Pj();
+ result.setPj(rs.getString("pj"));
+ result.setPath(rs.getString("path"));
+ result.setUrl(rs.getString("url"));
+ result.setDes(rs.getString("des"));
+ result.setType(rs.getString("type"));
+ return result;
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ */
+ public void delete(String pj) {
+ String sql = "delete from pj where pj = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 增加项目
+ *
+ * @param pj
+ * 项目
+ * @return 影响数量
+ */
+ public int insert(Pj pj) {
+ String sql = "insert into pj (pj,path,url,des,type) values (?,?,?,?,?)";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj.getPj());
+ pstmt.setString(index++, pj.getPath());
+ pstmt.setString(index++, pj.getUrl());
+ pstmt.setString(index++, pj.getDes());
+ pstmt.setString(index++, pj.getType());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 保存项目
+ *
+ * @param pj
+ * 项目
+ * @return 影响数量
+ */
+ public int update(Pj pj) {
+ String sql = "update pj set path=?,url=?,des=?,type=? where pj = ?";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj.getPath());
+ pstmt.setString(index++, pj.getUrl());
+ pstmt.setString(index++, pj.getDes());
+ pstmt.setString(index++, pj.getType());
+ pstmt.setString(index++, pj.getPj());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 获取具有相同路径或访问地址的项目数量
+ *
+ * @param path
+ * 路径
+ * @param url
+ * 访问地址
+ * @return 具有相同路径或访问地址的项目数量
+ */
+ public int getCount(String path, String url) {
+ String sql = "select count(1) from pj where path=? or url=?";//TODO 大小写敏感?
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, path);
+ pstmt.setString(index++, url);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/PjGrDao.java b/src/main/java/org/svnadmin/dao/PjGrDao.java
new file mode 100644
index 0000000..e35ba4f
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/PjGrDao.java
@@ -0,0 +1,206 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+import org.svnadmin.entity.PjGr;
+
+/**
+ * 项目组
+ *
+ * @author Huiwu Yuan
+ *
+ */
+@Repository(PjGrDao.BEAN_NAME)
+public class PjGrDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjGrDao";
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 项目组
+ */
+ public PjGr get(String pj, String gr) {
+ String sql = "select pj,gr,des from pj_gr where pj = ? and gr=?";
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPjGr(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目组列表
+ */
+ public List getList(String pj) {
+ String sql = "select pj,gr,des from pj_gr where pj=? order by pj,gr";
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjGr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rs
+ * ResultSet
+ * @return 项目组
+ * @throws SQLException
+ * jdbc异常
+ */
+ PjGr readPjGr(ResultSet rs) throws SQLException {
+ PjGr result = new PjGr();
+ result.setPj(rs.getString("pj"));
+ result.setGr(rs.getString("gr"));
+ result.setDes(rs.getString("des"));
+ return result;
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ */
+ public void delete(String pj, String gr) {
+ String sql = "delete from pj_gr where pj = ? and gr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ */
+ public void deletePj(String pj) {
+ String sql = "delete from pj_gr where pj = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 保存
+ *
+ * @param pjGr
+ * 项目组
+ */
+ public void save(PjGr pjGr) {
+ if (this.get(pjGr.getPj(), pjGr.getGr()) == null) {
+ String sql = "insert into pj_gr (pj,gr,des) values (?,?,?)";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjGr.getPj());
+ pstmt.setString(index++, pjGr.getGr());
+ pstmt.setString(index++, pjGr.getDes());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ } else {
+ String sql = "update pj_gr set des=? where pj = ? and gr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjGr.getDes());
+ pstmt.setString(index++, pjGr.getPj());
+ pstmt.setString(index++, pjGr.getGr());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/PjGrUsrDao.java b/src/main/java/org/svnadmin/dao/PjGrUsrDao.java
new file mode 100644
index 0000000..d81acb9
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/PjGrUsrDao.java
@@ -0,0 +1,320 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.entity.PjGrUsr;
+
+/**
+ * 项目的组的用户
+ *
+ * @author Huiwu Yuan
+ *
+ */
+@Repository(PjGrUsrDao.BEAN_NAME)
+public class PjGrUsrDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjGrUsrDao";
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param usr
+ * 用户
+ * @return 组用户
+ */
+ public PjGrUsr get(String pj, String gr, String usr) {
+ String sql = "select a.pj,a.usr,a.gr,b.name as usrname from pj_gr_usr a left join usr b on (a.usr=b.usr) where a.pj = ? and a.gr=? and a.usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+ pstmt.setString(index++, usr);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPjGrUsr(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 组用户列表
+ */
+ public List getList(String pj, String gr) {
+ String sql = "select a.pj,a.usr,a.gr,b.name as usrname from pj_gr_usr a left join usr b on (a.usr = b.usr) where a.pj=? and a.gr=? order by a.usr";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjGrUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * 项目的组用户列表(用户可能为空),导出authz文件时使用
+ *
+ * @param pj
+ * 项目
+ * @return 项目的组用户列表
+ */
+ public List getList(String pj) {
+ // String sql =
+ // "select pj,usr,gr from pj_gr_usr where pj=? order by gr,usr";
+ String sql = "select a.pj,a.gr,b.usr,c.name as usrname from pj_gr a left join pj_gr_usr b on (a.pj=b.pj and a.gr=b.gr) left join usr c on (b.usr = c.usr) where a.pj=? order by a.gr,b.usr";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjGrUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * 有相同的svn root的项目的组用户列表(用户可能为空),导出authz文件时使用
+ *
+ * @param rootPath
+ * svn root
+ * @return 有相同的svn root的项目组用户
+ */
+ public List getListByRootPath(String rootPath) {
+ // String sql =
+ // "select pj,usr,gr from pj_gr_usr where pj in (select distinct pj from pj where type=? and path like ?) order by pj,gr,usr";
+ String sql = "select a.pj,a.gr,b.usr,c.name as usrname from pj_gr a left join pj_gr_usr b on (a.pj=b.pj and a.gr=b.gr) left join usr c on (b.usr=c.usr) "
+ + " where a.pj in (select distinct pj from pj where type=? and path like ?) order by a.pj,a.gr,b.usr";
+ List list = new ArrayList();
+
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, Constants.HTTP_MUTIL);
+ pstmt.setString(index++, rootPath + "%");//TODO 大小写敏感?
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjGrUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rs
+ * ResultSet
+ * @return 组用户
+ * @throws SQLException
+ * jdbc异常
+ */
+ PjGrUsr readPjGrUsr(ResultSet rs) throws SQLException {
+ PjGrUsr result = new PjGrUsr();
+ result.setPj(rs.getString("pj"));
+ result.setUsr(rs.getString("usr"));
+ result.setGr(rs.getString("gr"));
+ result.setUsrName(rs.getString("usrname"));
+ return result;
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param usr
+ * 用户
+ */
+ public void delete(String pj, String gr, String usr) {
+ String sql = "delete from pj_gr_usr where pj = ? and gr=? and usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除
+ *
+ * @param usr
+ * 用户
+ */
+ public void deleteUsr(String usr) {
+ String sql = "delete from pj_gr_usr where usr = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ */
+ public void deletePjGr(String pj, String gr) {
+ String sql = "delete from pj_gr_usr where pj = ? and gr = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ */
+ public void deletePj(String pj) {
+ String sql = "delete from pj_gr_usr where pj = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 保存
+ *
+ * @param pjGrUsr
+ * 项目用户
+ */
+ public void save(PjGrUsr pjGrUsr) {
+ if (this.get(pjGrUsr.getPj(), pjGrUsr.getGr(), pjGrUsr.getUsr()) == null) {
+ String sql = "insert into pj_gr_usr (pj,usr,gr) values (?,?,?)";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjGrUsr.getPj());
+ pstmt.setString(index++, pjGrUsr.getUsr());
+ pstmt.setString(index++, pjGrUsr.getGr());
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/PjUsrDao.java b/src/main/java/org/svnadmin/dao/PjUsrDao.java
new file mode 100644
index 0000000..29f60df
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/PjUsrDao.java
@@ -0,0 +1,240 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+import org.svnadmin.entity.PjUsr;
+
+/**
+ *
+ * 项目的用户。 只对单库方式有用,包括svn协议和http协议(单库),可以每个项目设置用户的密码。
+ *
+ * @author Huiwu Yuan
+ *
+ */
+@Repository(PjUsrDao.BEAN_NAME)
+public class PjUsrDao extends Dao {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjUsrDao";
+
+ /**
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ * @return 项目用户
+ */
+ public PjUsr get(String pj, String usr) {
+ String sql = "select a.pj,a.usr,a.psw,b.name as usrname from pj_usr a left join usr b on (a.usr = b.usr) where a.pj = ? and a.usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, usr);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readPjUsr(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目的用户列表
+ */
+ public List getList(String pj) {
+ String sql = "select a.pj,a.usr,a.psw,b.name usrname from pj_usr a left join usr b on (a.usr = b.usr) where a.pj = ?";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readPjUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rs
+ * ResultSet
+ * @return PjUsr
+ * @throws SQLException
+ * jdbc异常
+ */
+ PjUsr readPjUsr(ResultSet rs) throws SQLException {
+ PjUsr result = new PjUsr();
+ result.setPj(rs.getString("pj"));
+ result.setUsr(rs.getString("usr"));
+ result.setName(rs.getString("usrname"));
+ result.setPsw(rs.getString("psw"));
+ return result;
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ */
+ public void delete(String pj, String usr) {
+ String sql = "delete from pj_usr where pj = ? and usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除这个项目的用户
+ *
+ * @param pj
+ * 项目
+ */
+ public void deletePj(String pj) {
+ String sql = "delete from pj_usr where pj = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 删除用户
+ *
+ * @param usr
+ * 用户
+ */
+ public void deleteUsr(String usr) {
+ String sql = "delete from pj_usr where usr = ?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 增加一条记录
+ *
+ * @param pjUsr
+ * 项目用户
+ * @return 成功数量
+ */
+ public int insert(PjUsr pjUsr) {
+ String sql = "insert into pj_usr (pj,usr,psw) values (?,?,?)";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjUsr.getPj());
+ pstmt.setString(index++, pjUsr.getUsr());
+ pstmt.setString(index++, pjUsr.getPsw());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+
+ }
+
+ /**
+ * 更新用户
+ *
+ * @param pjUsr
+ * 项目用户
+ * @return 更新的数量
+ */
+ public int update(PjUsr pjUsr) {
+ String sql = "update pj_usr set psw=? where pj = ? and usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pjUsr.getPsw());
+ pstmt.setString(index++, pjUsr.getPj());
+ pstmt.setString(index++, pjUsr.getUsr());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/dao/UsrDao.java b/src/main/java/org/svnadmin/dao/UsrDao.java
new file mode 100644
index 0000000..e8ec454
--- /dev/null
+++ b/src/main/java/org/svnadmin/dao/UsrDao.java
@@ -0,0 +1,326 @@
+package org.svnadmin.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.entity.Usr;
+
+/**
+ * 用户DAO
+ *
+ * @author Huiwu Yuan
+ *
+ */
+@Repository(UsrDao.BEAN_NAME)
+public class UsrDao extends Dao {
+
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "usrDao";
+
+ /**
+ * 获取一个用户
+ *
+ * @param usr
+ * 用户
+ * @return 用户
+ */
+ public Usr get(String usr) {
+ String sql = "select usr,name,psw,role from usr where usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return readUsr(rs);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return null;
+ }
+
+ /**
+ * @return 所有用户列表
+ */
+ public List getList() {
+ String sql = "select usr,name,psw,role from usr order by usr";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * 获取这个项目组未选的用户(不包括*)
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 项目组未选的用户(不包括*)
+ */
+ public List listUnSelected(String pj, String gr) {
+ String sql = "select usr,name,psw,role from usr a where a.usr <> '*' "
+ + " and not exists (select usr from pj_gr_usr b where a.usr = b.usr and b.pj=? and b.gr=?) order by a.usr";
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, gr);
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 所有项目用户列表(不包括*)
+ */
+ public List getList(String pj) {
+ String sql = "select p.usr,p.name,p.role,CASE WHEN pu.psw IS NOT NULL THEN pu.psw ELSE p.psw END psw from ("
+ + " select a.usr,a.role,a.psw,a.name from usr a "
+ + " where "
+ + " exists (select d.usr from pj_gr_usr d where d.usr=a.usr and d.pj=?) "
+ + " or exists(select c.usr from pj_usr_auth c where a.usr=c.usr and c.pj=?) "
+ + " ) p "
+ + " left join pj_usr pu on (p.usr=pu.usr and pu.pj=?) where p.usr <> '*'"
+ + " order by p.usr ";
+
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, pj);
+ pstmt.setString(index++, pj);
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * @param rootPath
+ * 项目所在的svn root
+ * @return 所有相同svn root的项目的用户列表(不包括*)
+ */
+ public List getListByRootPath(String rootPath) {
+ String sql = "select p.usr,p.name,p.role,CASE WHEN pu.psw IS NOT NULL THEN pu.psw ELSE p.psw END psw from ("
+ + " select a.usr,a.role,a.psw,a.name from usr a "
+ + " where "
+ + " exists (select d.usr from pj_gr_usr d where d.usr=a.usr and d.pj in (select distinct pj from pj where type=? and path like ?)) "
+ + " or exists(select c.usr from pj_usr_auth c where a.usr=c.usr and c.pj in (select distinct pj from pj where type=? and path like ?)) "
+ + " ) p "
+ + " left join pj_usr pu on (p.usr=pu.usr) where p.usr <> '*'"
+ + " order by p.usr ";
+
+ List list = new ArrayList();
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, Constants.HTTP_MUTIL);
+ pstmt.setString(index++, rootPath + "%");//TODO 大小写敏感?
+ pstmt.setString(index++, Constants.HTTP_MUTIL);
+ pstmt.setString(index++, rootPath + "%");//TODO 大小写敏感?
+
+ rs = pstmt.executeQuery();
+ while (rs.next()) {
+ list.add(readUsr(rs));
+ }
+ return list;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ }
+
+ /**
+ * 从ResultSet中读取Usr对象
+ *
+ * @param rs
+ * ResultSet
+ * @return Usr对象
+ * @throws SQLException
+ * JDBC异常
+ */
+ Usr readUsr(ResultSet rs) throws SQLException {
+ Usr result = new Usr();
+ result.setUsr(rs.getString("usr"));
+ result.setName(rs.getString("name"));
+ result.setPsw(rs.getString("psw"));
+ result.setRole(rs.getString("role"));
+ return result;
+ }
+
+ /**
+ * 删除用户
+ *
+ * @param usr
+ * 用户
+ */
+ public void delete(String usr) {
+ String sql = "delete from usr where usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr);
+
+ pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 更新用户
+ *
+ * @param usr
+ * 用户
+ * @return 更新数量
+ */
+ public int update(Usr usr) {
+ String sql = "update usr set psw=?,name=?,role=? where usr=?";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr.getPsw());
+ pstmt.setString(index++, usr.getName());
+ pstmt.setString(index++, usr.getRole());
+ pstmt.setString(index++, usr.getUsr());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * 增加一个用户
+ *
+ * @param usr
+ * 用户
+ * @return 更新数量
+ */
+ public int insert(Usr usr) {
+ String sql = "insert into usr (usr,psw,name,role) values (?,?,?,?)";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+ int index = 1;
+ pstmt.setString(index++, usr.getUsr());
+ pstmt.setString(index++, usr.getPsw());
+ pstmt.setString(index++, usr.getName());
+ pstmt.setString(index++, usr.getRole());
+
+ return pstmt.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(null, pstmt, conn);
+ }
+ }
+
+ /**
+ * @return 总数(不包括*)
+ */
+ public int getCount() {
+ String sql = "select count(1) from usr where usr <> '*'";
+ Connection conn = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try {
+ conn = this.getConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ this.close(rs, pstmt, conn);
+ }
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/svnadmin/entity/Ajax.java b/src/main/java/org/svnadmin/entity/Ajax.java
new file mode 100644
index 0000000..c11497f
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/Ajax.java
@@ -0,0 +1,66 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * ajax服务层返回的结果
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ */
+public class Ajax implements Serializable{
+ /**
+ * 序列化ID
+ */
+ private static final long serialVersionUID = -545103916156321718L;
+ /**
+ * content type
+ */
+ private String contentType;
+ /**
+ * 结果
+ */
+ private String result;
+
+ /**
+ * 默认构造函数
+ */
+ public Ajax() {
+ }
+
+
+ /**
+ * 构造函数
+ * @param contentType content type
+ * @param result 结果
+ */
+ public Ajax(String contentType,String result){
+ this.contentType=contentType;
+ this.result=result;
+ }
+
+ /**
+ * @return content type
+ */
+ public String getContentType() {
+ return contentType;
+ }
+ /**
+ * @param contentType content type
+ */
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+ /**
+ * @return 结果
+ */
+ public String getResult() {
+ return result;
+ }
+ /**
+ * @param result 结果
+ */
+ public void setResult(String result) {
+ this.result = result;
+ }
+}
diff --git a/src/main/java/org/svnadmin/entity/I18n.java b/src/main/java/org/svnadmin/entity/I18n.java
new file mode 100644
index 0000000..4760d4c
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/I18n.java
@@ -0,0 +1,84 @@
+/**
+ *
+ */
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * @author Harvey
+ * @since 3.0.2
+ *
+ */
+public class I18n implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8731707774048772734L;
+ /**
+ * 语言
+ */
+ private String lang;
+ /**
+ *
+ */
+ private String id;
+ /**
+ *
+ */
+ private String lbl;
+
+ /**
+ * ID对应的语言总数
+ */
+ private int total;
+ /**
+ * @return 语言
+ */
+ public String getLang() {
+ return lang;
+ }
+ /**
+ * @param lang 语言
+ */
+ public void setLang(String lang) {
+ this.lang = lang;
+ }
+ /**
+ * @return key
+ */
+ public String getId() {
+ return id;
+ }
+ /**
+ * @param id key
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+ /**
+ * @return label
+ */
+ public String getLbl() {
+ return lbl;
+ }
+ /**
+ * @param lbl label
+ */
+ public void setLbl(String lbl) {
+ this.lbl = lbl;
+ }
+ /**
+ * @return ID对应的语言总数
+ */
+ public int getTotal() {
+ return total;
+ }
+ /**
+ * @param total ID对应的语言总数
+ */
+ public void setTotal(int total) {
+ this.total = total;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/Pj.java b/src/main/java/org/svnadmin/entity/Pj.java
new file mode 100644
index 0000000..e5781c2
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/Pj.java
@@ -0,0 +1,132 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * 项目
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class Pj implements Serializable{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3570692240378418844L;
+ /**
+ * 项目ID
+ */
+ private String pj;
+ /**
+ * 仓库位置
+ */
+ private String path;
+ /**
+ * 访问项目的svn地址
+ */
+ private String url;
+ /**
+ * 描述
+ */
+ private String des;
+ /**
+ * 类型
+ */
+ private String type;
+
+ /**
+ * 用户是否是这个项目的管理员
+ */
+ private boolean manager;
+
+ /**
+ * @return 项目ID
+ */
+ public String getPj() {
+ return pj;
+ }
+
+ /**
+ * @param pj
+ * 项目ID
+ */
+ public void setPj(String pj) {
+ this.pj = pj;
+ }
+
+ /**
+ * @return 仓库位置
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @param path
+ * 仓库位置
+ */
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ /**
+ * @return 描述
+ */
+ public String getDes() {
+ return des;
+ }
+
+ /**
+ * @param des
+ * 描述
+ */
+ public void setDes(String des) {
+ this.des = des;
+ }
+
+ /**
+ * @return 类型
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * @param type
+ * 类型
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * @return 访问项目的svn地址
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * @param url
+ * 访问项目的svn地址
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * @return 用户是否是这个项目的管理员
+ */
+ public boolean isManager() {
+ return manager;
+ }
+
+ /**
+ * @param manager
+ * 用户是否是这个项目的管理员
+ */
+ public void setManager(boolean manager) {
+ this.manager = manager;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/PjAuth.java b/src/main/java/org/svnadmin/entity/PjAuth.java
new file mode 100644
index 0000000..8817fbc
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/PjAuth.java
@@ -0,0 +1,152 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * 权限
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class PjAuth implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8744287510861451872L;
+ /**
+ * 资源
+ */
+ private String res;
+ /**
+ * 项目
+ */
+ private String pj;
+ /**
+ * 组
+ */
+ private String gr;
+ /**
+ * 用户
+ */
+ private String usr;
+ /**
+ * 用户姓名
+ */
+ private String usrName;
+ /**
+ * r : 可读; w : 可写
+ */
+ private String rw;
+ /**
+ * 描述
+ */
+ private String des;
+
+ /**
+ * @return 资源
+ */
+ public String getRes() {
+ return res;
+ }
+
+ /**
+ * @param res
+ * 资源
+ */
+ public void setRes(String res) {
+ this.res = res;
+ }
+
+ /**
+ * @return 项目
+ */
+ public String getPj() {
+ return pj;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ */
+ public void setPj(String pj) {
+ this.pj = pj;
+ }
+
+ /**
+ * @return 组
+ */
+ public String getGr() {
+ return gr;
+ }
+
+ /**
+ * @param gr
+ * 组
+ */
+ public void setGr(String gr) {
+ this.gr = gr;
+ }
+
+ /**
+ * @return r : 可读; w : 可写
+ */
+ public String getRw() {
+ return rw;
+ }
+
+ /**
+ * @param rw
+ * r : 可读; w : 可写
+ */
+ public void setRw(String rw) {
+ this.rw = rw;
+ }
+
+ /**
+ * @return 用户
+ */
+ public String getUsr() {
+ return usr;
+ }
+
+ /**
+ * @param usr
+ * 用户
+ */
+ public void setUsr(String usr) {
+ this.usr = usr;
+ }
+
+ /**
+ *
+ * @return 用户姓名
+ */
+ public String getUsrName() {
+ return usrName;
+ }
+
+ /**
+ *
+ * @param usrName
+ * 用户姓名
+ */
+ public void setUsrName(String usrName) {
+ this.usrName = usrName;
+ }
+
+ /**
+ * @return 描述
+ */
+ public String getDes() {
+ return des;
+ }
+
+ /**
+ * @param des
+ * 描述
+ */
+ public void setDes(String des) {
+ this.des = des;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/PjGr.java b/src/main/java/org/svnadmin/entity/PjGr.java
new file mode 100644
index 0000000..40d1951
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/PjGr.java
@@ -0,0 +1,74 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * 组
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class PjGr implements Serializable{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6413099229527347938L;
+ /**
+ * 项目
+ */
+ private String pj;
+ /**
+ * 组
+ */
+ private String gr;
+ /**
+ * 描述
+ */
+ private String des;
+
+ /**
+ * @return 项目
+ */
+ public String getPj() {
+ return pj;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ */
+ public void setPj(String pj) {
+ this.pj = pj;
+ }
+
+ /**
+ * @return 描述
+ */
+ public String getDes() {
+ return des;
+ }
+
+ /**
+ * @param des
+ * 描述
+ */
+ public void setDes(String des) {
+ this.des = des;
+ }
+
+ /**
+ * @return 组
+ */
+ public String getGr() {
+ return gr;
+ }
+
+ /**
+ * @param gr
+ * 组
+ */
+ public void setGr(String gr) {
+ this.gr = gr;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/PjGrUsr.java b/src/main/java/org/svnadmin/entity/PjGrUsr.java
new file mode 100644
index 0000000..cdd89dc
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/PjGrUsr.java
@@ -0,0 +1,93 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * 项目组用户
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class PjGrUsr implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2031955995574649327L;
+ /**
+ * 项目
+ */
+ private String pj;
+ /**
+ * 用户
+ */
+ private String usr;
+ /**
+ * 用户姓名
+ */
+ private String usrName;
+ /**
+ * 组
+ */
+ private String gr;
+
+ /**
+ * @return 项目
+ */
+ public String getPj() {
+ return pj;
+ }
+
+ /**
+ * @param pj
+ * 项目
+ */
+ public void setPj(String pj) {
+ this.pj = pj;
+ }
+
+ /**
+ * @return 用户
+ */
+ public String getUsr() {
+ return usr;
+ }
+
+ /**
+ * @return 用户姓名
+ */
+ public String getUsrName() {
+ return usrName;
+ }
+
+ /**
+ * @param usrName
+ * 用户姓名
+ */
+ public void setUsrName(String usrName) {
+ this.usrName = usrName;
+ }
+
+ /**
+ * @param usr
+ * 用户
+ */
+ public void setUsr(String usr) {
+ this.usr = usr;
+ }
+
+ /**
+ * @return 组
+ */
+ public String getGr() {
+ return gr;
+ }
+
+ /**
+ * @param gr
+ * 组
+ */
+ public void setGr(String gr) {
+ this.gr = gr;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/PjUsr.java b/src/main/java/org/svnadmin/entity/PjUsr.java
new file mode 100644
index 0000000..1c0ad5f
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/PjUsr.java
@@ -0,0 +1,34 @@
+package org.svnadmin.entity;
+
+/**
+ * 项目用户 。只对单库方式有用,包括svn协议和http协议(单库),可以每个项目设置用户的密码
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class PjUsr extends Usr {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5863709168694149752L;
+ /**
+ * 项目ID
+ */
+ private String pj;
+
+ /**
+ * @return 项目ID
+ */
+ public String getPj() {
+ return pj;
+ }
+
+ /**
+ * @param pj
+ * 项目ID
+ */
+ public void setPj(String pj) {
+ this.pj = pj;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/entity/Usr.java b/src/main/java/org/svnadmin/entity/Usr.java
new file mode 100644
index 0000000..a6c7a76
--- /dev/null
+++ b/src/main/java/org/svnadmin/entity/Usr.java
@@ -0,0 +1,94 @@
+package org.svnadmin.entity;
+
+import java.io.Serializable;
+
+/**
+ * 用户
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class Usr implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8251147689572549482L;
+ /**
+ * 用户ID
+ */
+ private String usr;
+ /**
+ * 用户姓名
+ */
+ private String name;
+ /**
+ * 密码(加密)
+ */
+ private String psw;
+ /**
+ * 角色
+ */
+ private String role;
+
+ /**
+ * @return 用户ID
+ */
+ public String getUsr() {
+ return usr;
+ }
+
+ /**
+ * @param usr
+ * 用户ID
+ */
+ public void setUsr(String usr) {
+ this.usr = usr;
+ }
+
+ /**
+ * @return 用户姓名
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name
+ * 用户姓名
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return 密码(加密)
+ */
+ public String getPsw() {
+ return psw;
+ }
+
+ /**
+ * @param psw
+ * 密码(加密)
+ */
+ public void setPsw(String psw) {
+ this.psw = psw;
+ }
+
+ /**
+ * @return 角色
+ */
+ public String getRole() {
+ return role;
+ }
+
+ /**
+ * @param role
+ * 角色
+ */
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/exceptions/TimeoutException.java b/src/main/java/org/svnadmin/exceptions/TimeoutException.java
new file mode 100644
index 0000000..29db02c
--- /dev/null
+++ b/src/main/java/org/svnadmin/exceptions/TimeoutException.java
@@ -0,0 +1,24 @@
+package org.svnadmin.exceptions;
+
+/**
+ * 超时异常
+ *
+ * @author Huiwu Yuan
+ *
+ */
+public class TimeoutException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param string
+ * 消息
+ */
+ public TimeoutException(String string) {
+ super(string);
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/service/AjaxService.java b/src/main/java/org/svnadmin/service/AjaxService.java
new file mode 100644
index 0000000..72eaf75
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/AjaxService.java
@@ -0,0 +1,41 @@
+package org.svnadmin.service;
+
+import java.util.Map;
+
+import org.svnadmin.entity.Ajax;
+
+/**
+ * ajax服务层接口
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ */
+public interface AjaxService {
+ /**
+ * html
+ */
+ public static final String CONTENTTYPE_HTML="text/html; charset=UTF-8";
+ /**
+ * xml
+ */
+ public static final String CONTENTTYPE_XML="text/xml; charset=UTF-8";
+ /**
+ * json
+ */
+ public static final String CONTENTTYPE_JSON="application/json; charset=UTF-8";
+ /**
+ * javascript
+ */
+ public static final String CONTENTTYPE_JAVASCRIPT="text/javascript; charset=UTF-8";
+ /**
+ * text
+ */
+ public static final String CONTENTTYPE_TEXT="text/plain; charset=UTF-8";
+
+ /**
+ * 执行逻辑
+ * @param parameters 参数
+ * @return 结果
+ */
+ Ajax execute(Map parameters);
+}
diff --git a/src/main/java/org/svnadmin/service/DefaultTreeFactory.java b/src/main/java/org/svnadmin/service/DefaultTreeFactory.java
new file mode 100644
index 0000000..89dff22
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/DefaultTreeFactory.java
@@ -0,0 +1,115 @@
+/**
+ *
+ */
+package org.svnadmin.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.svnadmin.common.util.SpringUtils;
+import org.tree.entity.Tree;
+import org.tree.service.TreeFactory;
+import org.tree.service.TreeNodeService;
+
+//TODO 提供JdbcTreeFactory,把树配置数据保存在数据库。
+
+/**
+ * 默认的树工厂类
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public class DefaultTreeFactory implements TreeFactory {
+
+ /**
+ * 单例
+ */
+ private static DefaultTreeFactory instance = new DefaultTreeFactory();
+
+ /**
+ *
+ */
+ private DefaultTreeFactory(){
+
+ }
+
+ /**
+ * @return the instance
+ */
+ public static DefaultTreeFactory getInstance() {
+ return instance;
+ }
+
+ public TreeNodeService findTreeNodeService(Tree tree) {
+ return SpringUtils.getBean(tree.getTreeNodeService());
+ }
+
+ public Tree find(String id) {
+ for(Tree tree:datas){
+ if(tree.getId().equals(id)){
+ //要给leaf设值
+ if(tree.getId().equals(tree.getParentId())){
+ tree.setLeaf(false);
+ }else{
+ tree.setLeaf(findChildren(tree.getId()).size()==0);
+ }
+ return tree;
+ }
+ }
+ return null;
+ }
+
+ public List findChildren(String parentId) {
+ List results = new ArrayList();
+ for(Tree tree:datas){
+ if(parentId.equals(tree.getParentId())){
+ //要给leaf设值
+ if(tree.getId().equals(tree.getParentId())){
+ tree.setLeaf(false);
+ results.add(tree);
+ return results;
+ }else{
+ tree.setLeaf(findChildren(tree.getId()).size()==0);
+ results.add(tree);
+ }
+ }
+ }
+ return results;
+ }
+
+
+ /**
+ *
+ */
+ private static List datas = new ArrayList();
+ static{
+ /*
+ * rep
+ * |rep
+ * | |rep
+ * | |rep
+ * |rep
+ * |
+ * rep
+ * |
+ */
+ datas.add(new Tree("rep","rep",RepTreeNodeService.BEAN_NAME));
+ /*
+ * com
+ * |_dept
+ * | |_dept user
+ * | |_dept user
+ * |_dept
+ * |_com user
+ * |_com user
+ *
+ */
+// datas.add(new Tree("com",null));
+
+// datas.add(new Tree("dept","com"));
+// datas.add(new Tree("user","com"));
+
+// datas.add(new Tree("user","dept"));
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/service/DefaultTreeService.java b/src/main/java/org/svnadmin/service/DefaultTreeService.java
new file mode 100644
index 0000000..000a90e
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/DefaultTreeService.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package org.svnadmin.service;
+
+import java.util.Map;
+
+import org.springframework.stereotype.Service;
+import org.svnadmin.entity.Ajax;
+import org.tree.service.AbstractTreeService;
+import org.tree.service.TreeFactory;
+
+/**
+ * 默认的树服务层
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+@Service(DefaultTreeService.BEAN_NAME)
+public class DefaultTreeService extends AbstractTreeService implements AjaxService{
+
+ /**
+ * Bean名称s
+ */
+ public static final String BEAN_NAME="ajaxTreeService";
+
+ public TreeFactory getTreeFactory() {
+ return DefaultTreeFactory.getInstance();
+ }
+
+ public Ajax execute(Map parameters) {
+ Ajax result = new Ajax();
+ result.setContentType(CONTENTTYPE_HTML);
+ result.setResult(this.getHTML(parameters));
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/service/I18nService.java b/src/main/java/org/svnadmin/service/I18nService.java
new file mode 100644
index 0000000..119d5d1
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/I18nService.java
@@ -0,0 +1,131 @@
+/**
+ *
+ */
+package org.svnadmin.service;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.dao.I18nDao;
+import org.svnadmin.entity.I18n;
+
+/**
+ * 多语言
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+@Service(I18nService.BEAN_NAME)
+public class I18nService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME="i18nService";
+
+ /**
+ * DAO
+ */
+ @Resource(name=I18nDao.BEAN_NAME)
+ protected I18nDao i18nDao;
+
+
+ /**
+ * @param lang 语言
+ * @param id 键值
+ * @return I18n
+ */
+ public I18n getI18n(String lang, String id) {
+ return i18nDao.get(lang, id);
+ }
+ /**
+ * @param i18n 多语言
+ */
+ @Transactional(propagation=Propagation.REQUIRES_NEW)
+ public void insert(I18n i18n) {
+ i18nDao.insert(i18n);
+ }
+ /**
+ * 更新
+ * @param i18n 多语言
+ */
+ @Transactional
+ public void update(I18n i18n){
+ i18nDao.update(i18n);
+ }
+ /**
+ * 是否存在这种语言
+ * @param lang 语言
+ * @return true表示数据库存在这个语言,否则返回false
+ */
+ public boolean existsLang(String lang) {
+ return i18nDao.existsLang(lang);
+ }
+
+ /**
+ * @return 获取系统现有的语言
+ */
+ public List getLangs(){
+ return this.i18nDao.getLangs();
+ }
+ /**
+ * @param id 键值
+ * @return 相同键值的语言列表
+ */
+ public Map getI18ns(String id) {
+ return i18nDao.getI18ns(id);
+ }
+ /**
+ * @return 键值列表
+ */
+ public List getIds() {
+ return this.i18nDao.getIds();
+ }
+ /**
+ * 获取导出的脚步语句
+ * @return 多语言列表
+ */
+ public String getInsertInto() {
+ List i18nList = this.i18nDao.getList();
+ if(i18nList!=null && !i18nList.isEmpty()){
+ StringBuffer content = new StringBuffer();
+ for (I18n i18n : i18nList) {
+ content.append("insert into i18n (lang,id,lbl) values (");
+ content.append("'").append(StringUtils.replace(i18n.getLang(), "'", "''")).append("',");
+ content.append("'").append(StringUtils.replace(i18n.getId(), "'", "''")).append("',");
+ content.append("'").append(StringUtils.replace(i18n.getLbl(), "'", "''")).append("'");
+ content.append(");\n");
+ }
+ return content.toString();
+ }
+ return null;
+ }
+ /**
+ * @param list 保存的列表
+ */
+ @Transactional
+ public void save(List list) {
+ for (I18n i18n : list) {
+ this.save(i18n);
+ }
+ }
+
+ /**
+ * 保存
+ * @param i18n 语言
+ */
+ @Transactional
+ public void save(I18n i18n){
+ if(this.getI18n(i18n.getLang(), i18n.getId())!=null){//已经存在
+ this.update(i18n);
+ }else{
+ this.insert(i18n);
+ }
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/PjAuthService.java b/src/main/java/org/svnadmin/service/PjAuthService.java
new file mode 100644
index 0000000..acc71fc
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/PjAuthService.java
@@ -0,0 +1,184 @@
+package org.svnadmin.service;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.dao.PjAuthDao;
+import org.svnadmin.dao.PjDao;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+
+/**
+ * 项目权限
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(PjAuthService.BEAN_NAME)
+public class PjAuthService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjAuthService";
+
+ /**
+ * 项目权限DAO
+ */
+ @Resource(name=PjAuthDao.BEAN_NAME)
+ protected PjAuthDao pjAuthDao;
+
+ /**
+ * 项目DAO
+ */
+ @Resource(name=PjDao.BEAN_NAME)
+ protected PjDao pjDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name=SvnService.BEAN_NAME)
+ protected SvnService svnService;
+
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目的资源列表
+ */
+ public List getResList(String pj) {
+ return pjAuthDao.getResList(pj);
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @param res 资源
+ * @return 项目资源的权限列表
+ */
+ public List list(String pj,String res) {
+ if(StringUtils.isBlank(res)){
+ return pjAuthDao.getList(pj);
+ }
+ return pjAuthDao.getList(pj,res);
+ }
+
+ /**
+ * 删除项目 组资源的权限
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param res
+ * 资源
+ */
+ @Transactional
+ public void deleteByGr(String pj, String gr,String res) {
+ pjAuthDao.deleteByGr(pj, gr, res);
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 删除项目用户资源的权限
+ *
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ * @param res
+ * 资源
+ */
+ @Transactional
+ public void deleteByUsr(String pj, String usr,String res) {
+ pjAuthDao.deleteByUsr(pj, usr, res);
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 保存
+ * @param pj 项目
+ * @param res 资源
+ * @param rw 可读可写
+ * @param grs 组
+ * @param usrs 用户
+ */
+ @Transactional
+ public void save(String pj,String res,String rw, String[] grs, String[] usrs) {
+ res = this.formatRes(pj, res);//如果资源没有[],自动加上
+ //gr
+ if(grs!=null){
+ for (String gr : grs) {
+ if(StringUtils.isBlank(gr)){
+ continue;
+ }
+ PjAuth pjAuth = new PjAuth();
+ pjAuth.setPj(pj);
+ pjAuth.setRes(res);
+ pjAuth.setRw(rw);
+ pjAuth.setGr(gr);
+ pjAuthDao.saveByGr(pjAuth);
+ }
+ }
+ //usr
+ if(usrs!=null){
+ for (String usr : usrs) {
+ if(StringUtils.isBlank(usr)){
+ continue;
+ }
+ PjAuth pjAuth = new PjAuth();
+ pjAuth.setPj(pj);
+ pjAuth.setRes(res);
+ pjAuth.setRw(rw);
+ pjAuth.setUsr(usr);
+ pjAuthDao.saveByUsr(pjAuth);
+ }
+ }
+ //export
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 格式化资源.如果资源没有[],自动加上[relateRoot:/]
+ * @param pj 项目id
+ * @param res 资源
+ * @return 格式化后的资源
+ * @since 3.0.3
+ */
+ public String formatRes(String pj,String res){
+ //如果资源没有[],自动加上
+// if(!res.startsWith("[") && !res.endsWith("]")){
+ return this.formatRes(this.pjDao.get(pj), res);
+// }
+// return res;
+ }
+ /**
+ * 格式化资源.如果资源没有[],自动加上[relateRoot:/]
+ * @param pj 项目
+ * @param res 资源
+ * @return 格式化后的资源
+ * @since 3.0.3
+ */
+ public String formatRes(Pj pj,String res){
+ //去除[xxx:],重新加上[relateRoot:/],防止跨项目授权
+ res = StringUtils.replaceEach(res, new String[]{"[","]"}, new String[]{"",""});
+ if (res.indexOf(":")!=-1) {
+ res = StringUtils.substringAfter(res, ":");
+ }
+
+ //如果资源没有[],自动加上
+ String relateRoot = PjService.getRelateRootPath(pj);
+ if(!res.startsWith("[") && !res.endsWith("]")){
+ if(res.startsWith("/")){
+ return "["+relateRoot+":"+res+"]";
+ }else{
+ return "["+relateRoot+":/"+res+"]";
+ }
+ }
+ return res;
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/PjGrService.java b/src/main/java/org/svnadmin/service/PjGrService.java
new file mode 100644
index 0000000..70ab9ec
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/PjGrService.java
@@ -0,0 +1,100 @@
+package org.svnadmin.service;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.dao.PjAuthDao;
+import org.svnadmin.dao.PjGrDao;
+import org.svnadmin.dao.PjGrUsrDao;
+import org.svnadmin.entity.PjGr;
+
+/**
+ * 项目组服务层
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(PjGrService.BEAN_NAME)
+public class PjGrService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjGrService";
+
+ /**
+ * 项目组DAO
+ */
+ @Resource(name = PjGrDao.BEAN_NAME)
+ protected PjGrDao pjGrDao;
+
+ /**
+ * 项目组用户DAO
+ */
+ @Resource(name = PjGrUsrDao.BEAN_NAME)
+ protected PjGrUsrDao pjGrUsrDao;
+
+ /**
+ * 项目权限DAO
+ */
+ @Resource(name = PjAuthDao.BEAN_NAME)
+ protected PjAuthDao pjAuthDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name = SvnService.BEAN_NAME)
+ protected SvnService svnService;
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 项目组
+ */
+ public PjGr get(String pj, String gr) {
+ return pjGrDao.get(pj, gr);
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目组列表
+ */
+ public List list(String pj) {
+ return pjGrDao.getList(pj);
+ }
+
+ /**
+ * 删除项目组(同时删除项目组的权限,项目组的用户)
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ */
+ @Transactional
+ public void delete(String pj, String gr) {
+ pjAuthDao.deletePjGr(pj, gr);
+ pjGrUsrDao.deletePjGr(pj, gr);
+ pjGrDao.delete(pj, gr);
+
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 保存
+ *
+ * @param pjGr
+ * 项目组
+ */
+ @Transactional
+ public void save(PjGr pjGr) {
+ pjGrDao.save(pjGr);
+ svnService.exportConfig(pjGr.getPj());
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/PjGrUsrService.java b/src/main/java/org/svnadmin/service/PjGrUsrService.java
new file mode 100644
index 0000000..74d607e
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/PjGrUsrService.java
@@ -0,0 +1,130 @@
+package org.svnadmin.service;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.dao.PjGrUsrDao;
+import org.svnadmin.entity.PjGrUsr;
+import org.svnadmin.entity.Usr;
+
+/**
+ * 项目组用户服务层
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(PjGrUsrService.BEAN_NAME)
+public class PjGrUsrService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjGrUsrService";
+ /**
+ * 项目组用户DAO
+ */
+ @Resource(name = PjGrUsrDao.BEAN_NAME)
+ protected PjGrUsrDao pjGrUsrDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name = SvnService.BEAN_NAME)
+ protected SvnService svnService;
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param usr
+ * 用户
+ * @return 组用户
+ */
+ public PjGrUsr get(String pj, String gr, String usr) {
+ return pjGrUsrDao.get(pj, gr, usr);
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 组用户列表
+ */
+ public List list(String pj, String gr) {
+ return pjGrUsrDao.getList(pj, gr);
+ }
+
+ /**
+ * 保存
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param usrs
+ * 用户
+ */
+ @Transactional
+ public void save(String pj, String gr, String[] usrs) {
+
+ if (usrs == null || usrs.length == 0) {
+ return;
+ }
+
+ for (String usr : usrs) {
+ if (StringUtils.isBlank(usr)) {
+ continue;
+ }
+ PjGrUsr pjGrUsr = new PjGrUsr();
+ pjGrUsr.setPj(pj);
+ pjGrUsr.setGr(gr);
+ pjGrUsr.setUsr(usr);
+ pjGrUsrDao.save(pjGrUsr);
+ }
+ // export
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @param usr
+ * 用户
+ */
+ @Transactional
+ public void delete(String pj, String gr, String usr) {
+ pjGrUsrDao.delete(pj, gr, usr);
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 是否有项目管理员的权限
+ * @param usr 用户
+ * @param pj 项目
+ * @return 有权限返回true,否则返回false
+ */
+ public boolean hasManagerRight(Usr usr,String pj){
+ if (pj == null) {
+ return false;
+ }
+ // TODO delete me 为了兼容3.0版本 see: Issue 4
+ String gr = pj + "_" + Constants.GROUP_MANAGER;
+ if (this.get(pj, gr, usr.getUsr()) != null) {
+ return true;
+ }
+ // 3.0.1版本以后
+ gr = Constants.GROUP_MANAGER;
+ return this.get(pj, gr, usr.getUsr()) != null;
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/PjService.java b/src/main/java/org/svnadmin/service/PjService.java
new file mode 100644
index 0000000..b3094a8
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/PjService.java
@@ -0,0 +1,214 @@
+package org.svnadmin.service;
+
+import java.io.File;
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.dao.PjAuthDao;
+import org.svnadmin.dao.PjDao;
+import org.svnadmin.dao.PjGrDao;
+import org.svnadmin.dao.PjGrUsrDao;
+import org.svnadmin.dao.PjUsrDao;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+import org.svnadmin.entity.PjGr;
+import org.svnadmin.util.I18N;
+
+/**
+ * 项目服务层
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(PjService.BEAN_NAME)
+public class PjService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjService";
+
+ /**
+ * 项目DAO
+ */
+ @Resource(name = PjDao.BEAN_NAME)
+ protected PjDao pjDao;
+
+ /**
+ * 项目用户DAO
+ */
+ @Resource(name = PjUsrDao.BEAN_NAME)
+ protected PjUsrDao pjUsrDao;
+
+ /**
+ * 项目组DAO
+ */
+ @Resource(name = PjGrDao.BEAN_NAME)
+ protected PjGrDao pjGrDao;
+
+ /**
+ * 项目组用户DAO
+ */
+ @Resource(name = PjGrUsrDao.BEAN_NAME)
+ protected PjGrUsrDao pjGrUsrDao;
+
+ /**
+ * 项目权限DAO
+ */
+ @Resource(name = PjAuthDao.BEAN_NAME)
+ protected PjAuthDao pjAuthDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name = SvnService.BEAN_NAME)
+ protected SvnService svnService;
+ /**
+ * 权限服务层
+ */
+ @Resource(name = PjAuthService.BEAN_NAME)
+ protected PjAuthService pjAuthService;
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目
+ */
+ public Pj get(String pj) {
+ return pjDao.get(pj);
+ }
+
+ /**
+ * @return 项目列表
+ */
+ public List list() {
+ return pjDao.getList();
+ }
+
+ /**
+ * @param usr
+ * 用户
+ * @return 用户有权限的项目列表(用户是否是这个项目的管理员)
+ */
+ public List list(String usr) {
+ return pjDao.getList(usr);
+ }
+
+ /**
+ * 删除(同时删除项目权限,项目组用户,项目组,项目用户)
+ *
+ * @param pj
+ * 项目
+ */
+ @Transactional
+ public void delete(String pj) {
+ pjAuthDao.deletePj(pj);
+ pjGrUsrDao.deletePj(pj);
+ pjGrDao.deletePj(pj);
+ pjUsrDao.deletePj(pj);
+
+ svnService.exportConfig(pj);
+
+ pjDao.delete(pj);
+ }
+
+ /**
+ * 保存。
+ * 数据库里已经存在相同的路径或url的项目,不可以保存。
+ * 如果仓库不存在,自动创建。
+ * 如果是增加项目,自动创建默认3个组。
+ *
+ * @param pj
+ * 项目
+ */
+ @Transactional
+ public void save(Pj pj) {
+ // 路径 把\替换为/
+ if (StringUtils.isNotBlank(pj.getPath())) {
+ pj.setPath(StringUtils.replace(pj.getPath(), "\\", "/"));
+ }
+ // url 把\替换为/
+ if (StringUtils.isNotBlank(pj.getUrl())) {
+ pj.setUrl(StringUtils.replace(pj.getUrl(), "\\", "/"));
+ }
+
+ // 是否可以增加项目
+ boolean insert = pjDao.get(pj.getPj()) == null;
+ if (insert) {
+ // 数据库里已经存在相同的路径或url的项目
+ if (this.pjDao.getCount(pj.getPath(), pj.getUrl()) > 0) {
+ throw new RuntimeException(I18N.getLbl("pj.save.error.existPathOrUrl", "数据库里已经存在相同的路径或url的仓库项目,请检查路径或url"));
+ }
+ } else {
+ // 数据库里已经存在相同的路径或url的项目
+ if (this.pjDao.getCount(pj.getPath(), pj.getUrl()) > 1) {
+ throw new RuntimeException(I18N.getLbl("pj.save.error.existMutilPathOrUrl","数据库里已经存在多个相同的路径或url的仓库项目,请检查路径或url"));
+ }
+ }
+ // 创建仓库
+ File respository = new File(pj.getPath());
+ if (!respository.exists() || !respository.isDirectory()) {// 不存在仓库
+ RepositoryService.createLocalRepository(respository);
+ }
+ if (insert) {
+ // 增加默认的组
+ this.pjDao.insert(pj);
+ for (String gr : Constants.GROUPS) {
+ PjGr pjGr = new PjGr();
+ pjGr.setPj(pj.getPj());
+ pjGr.setGr(gr);
+ pjGr.setDes(gr);
+ pjGrDao.save(pjGr);
+ }
+ // 增加默认的权限 @see Issue 29
+ PjAuth pjAuth = new PjAuth();
+ pjAuth.setPj(pj.getPj());
+ pjAuth.setRes(this.pjAuthService.formatRes(pj, "/"));
+ pjAuth.setRw("rw");
+ pjAuth.setGr(Constants.GROUP_MANAGER);
+ pjAuthDao.saveByGr(pjAuth);
+
+ } else {
+ this.pjDao.update(pj);
+ }
+ svnService.exportConfig(pj.getPj());
+ }
+
+ /**
+ * 获取项目的相对根路径.例如项目的path=e:/svn/projar,则返回projar。如果path为空,则返回项目ID
+ * @param pj 项目id
+ * @return 项目的相对根路径
+ * @since 3.0.3
+ */
+ public String getRelateRootPath(String pj){
+ Pj p = this.get(pj);
+ if(p == null || StringUtils.isBlank(p.getPath())){
+ return pj;
+ }
+ return getRelateRootPath(pj);
+ }
+ /**
+ * 获取项目的相对根路径.例如项目的path=e:/svn/projar,则返回projar。如果path为空,则返回项目ID
+ * @param pj 项目
+ * @return 项目的相对根路径
+ * @since 3.0.3
+ */
+ public static String getRelateRootPath(Pj pj){
+ String path = pj.getPath();
+ if(StringUtils.isBlank(path)){
+ return pj.getPj();
+ }
+ path = StringUtils.replace(path, "\\", "/");
+
+ while(path.endsWith("/")){
+ path = path.substring(0, path.length()-1);
+ }
+
+ return StringUtils.substringAfterLast(path, "/");
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/PjUsrService.java b/src/main/java/org/svnadmin/service/PjUsrService.java
new file mode 100644
index 0000000..590d7f7
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/PjUsrService.java
@@ -0,0 +1,88 @@
+package org.svnadmin.service;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.dao.PjUsrDao;
+import org.svnadmin.entity.PjUsr;
+
+/**
+ * 项目用户服务层(采用svn或http单库方式是,用户可以对每个项目设置不用的密码)
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(PjUsrService.BEAN_NAME)
+public class PjUsrService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "pjUsrService";
+
+ /**
+ * 项目用户DAO
+ */
+ @Resource(name = PjUsrDao.BEAN_NAME)
+ protected PjUsrDao pjUsrDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name = SvnService.BEAN_NAME)
+ protected SvnService svnService;
+
+ /**
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ * @return 项目用户
+ */
+ public PjUsr get(String pj, String usr) {
+ return pjUsrDao.get(pj, usr);
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 项目的用户列表
+ */
+ public List list(String pj) {
+ return pjUsrDao.getList(pj);
+ }
+
+ /**
+ * 删除
+ *
+ * @param pj
+ * 项目
+ * @param usr
+ * 用户
+ */
+ @Transactional
+ public void delete(String pj, String usr) {
+ pjUsrDao.delete(pj, usr);
+
+ svnService.exportConfig(pj);
+ }
+
+ /**
+ * 保存
+ *
+ * @param pjUsr
+ * 项目用户
+ */
+ @Transactional
+ public void save(PjUsr pjUsr) {
+ if (this.pjUsrDao.get(pjUsr.getPj(), pjUsr.getUsr()) == null) {
+ this.pjUsrDao.insert(pjUsr);
+ } else {
+ this.pjUsrDao.update(pjUsr);
+ }
+ svnService.exportConfig(pjUsr.getPj());
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/RepTreeNodeService.java b/src/main/java/org/svnadmin/service/RepTreeNodeService.java
new file mode 100644
index 0000000..77a111f
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/RepTreeNodeService.java
@@ -0,0 +1,100 @@
+/**
+ *
+ */
+package org.svnadmin.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Service;
+import org.tmatesoft.svn.core.SVNDirEntry;
+import org.tmatesoft.svn.core.SVNNodeKind;
+import org.tree.entity.Tree;
+import org.tree.entity.TreeNode;
+import org.tree.service.AbstractTreeNodeService;
+
+/**
+ * 仓库目录结构树节点服务层
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+@Service(RepTreeNodeService.BEAN_NAME)
+public class RepTreeNodeService extends AbstractTreeNodeService {
+
+ private static final String AND = "$AND$";
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME="repTreeNodeService";
+ /**
+ * 日志
+ */
+ private final Logger LOG = Logger.getLogger(RepTreeNodeService.class);
+
+
+ /**
+ * 仓库服务层
+ */
+ @Resource(name=RepositoryService.BEAN_NAME)
+ RepositoryService repositoryService;
+
+ @Override
+ protected List getTreeNodes(Tree parent,
+ Map parameters) {
+ List results = new ArrayList();
+
+ String pj = (String) parameters.get("pj");
+ String path = (String) parameters.get("path");
+ path = StringUtils.replace(path, AND, "&");
+ if(StringUtils.isBlank(pj)){
+ LOG.warn("pj id is blank ");
+ return null;
+ }
+ try{
+ Collection entries = this.repositoryService.getDir(pj, path);
+ if(entries == null){
+ return null;
+ }
+// Collection entries = repository.getDir("/trunk", SVNRevision.HEAD.getNumber(), properties, (Collection) null);
+ for (SVNDirEntry svnDirEntry : entries) {
+// System.out.println(svnDirEntry);
+// System.out.println(svnDirEntry.getName()//文件夹或文件名
+// +","+svnDirEntry.getKind()//类型,参考SVNNodeKind.FILE,SVNNodeKind.DIR
+// +","+svnDirEntry.getRevision()//版本
+// +","+svnDirEntry.getAuthor()//作者
+// +","+svnDirEntry.getSize()//如果kind是SVNNodeKind.FILE时返回文件的大小
+// +","+svnDirEntry.getDate());//日期
+ TreeNode treeNode = new TreeNode(svnDirEntry.getName());
+ treeNode.setLeaf(SVNNodeKind.FILE.equals(svnDirEntry.getKind()));//叶子?
+ treeNode.addParamete("pj", pj);
+ if(path.endsWith("/")){
+ treeNode.addParamete("path", path+StringUtils.replace(svnDirEntry.getName(), "&", AND));
+ }else{
+ treeNode.addParamete("path", path+"/"+StringUtils.replace(svnDirEntry.getName(), "&", AND));
+ }
+ results.add(treeNode);
+ }
+ Collections.sort(results);// 排序
+ } catch (Exception e) {
+ LOG.error(e.getMessage());
+ e.printStackTrace();
+
+ results.clear();
+ TreeNode errorNode = new TreeNode(e.getMessage());
+ errorNode.setLeaf(true);
+ results.add(errorNode);
+ return results;
+ }
+
+ return results;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/service/RepositoryService.java b/src/main/java/org/svnadmin/service/RepositoryService.java
new file mode 100644
index 0000000..fdc7184
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/RepositoryService.java
@@ -0,0 +1,233 @@
+/**
+ *
+ */
+package org.svnadmin.service;
+
+import java.io.File;
+import java.util.Collection;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Service;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.dao.PjDao;
+import org.svnadmin.dao.PjUsrDao;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjUsr;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.util.EncryptUtil;
+import org.svnadmin.util.I18N;
+import org.svnadmin.util.UsrProvider;
+import org.tmatesoft.svn.core.SVNAuthenticationException;
+import org.tmatesoft.svn.core.SVNDirEntry;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNProperties;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
+import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
+import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
+import org.tmatesoft.svn.core.io.SVNRepository;
+import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
+import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNWCUtil;
+
+/**
+ * 仓库服务层
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+@Service(RepositoryService.BEAN_NAME)
+public class RepositoryService{
+
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME="repositoryService";
+ /**
+ * 日志
+ */
+ private final Logger LOG = Logger.getLogger(RepositoryService.class);
+
+
+ /**
+ * 项目DAO
+ */
+ @Resource(name=PjDao.BEAN_NAME)
+ PjDao pjDao;
+ /**
+ * 项目用户DAO
+ */
+ @Resource(name=PjUsrDao.BEAN_NAME)
+ PjUsrDao pjUsrDao;
+
+ /**
+ * 获取svn仓库
+ * @param pjId 项目ID
+ * @return svn仓库
+ * @throws SVNException svn异常,例如没有权限等
+ */
+ public SVNRepository getRepository(String pjId) throws SVNException{
+ Pj pj = pjDao.get(pjId);
+ if(pj == null){
+ LOG.warn("Not found project: "+pjId);
+ return null;
+ }
+ return this.getRepository(pj);
+ }
+
+ /**
+ * 从项目的url中获取svn的url
+ * @param url 项目url
+ * @return svn url
+ */
+ public static String parseURL(String url){
+ if(StringUtils.isBlank(url)){
+ return null;
+ }
+ String result = url.trim();//去空格
+ result = StringUtils.replace(result, "\t", " ");
+ result = StringUtils.replace(result, "\r", " ");
+ result = StringUtils.replace(result, "\n", " ");
+ result = StringUtils.replace(result, "\b", " ");
+ result = StringUtils.replace(result, "<", " ");//eg.
+ result = StringUtils.replace(result, "(", " ");//eg. ()
+
+ result = result.trim();
+ int blank = result.indexOf(" ");
+ if(blank != -1){
+ result = result.substring(0, blank);
+ }
+
+ return result;
+ }
+
+ /**
+ * 获取svn仓库
+ * @param pj 项目
+ * @return svn仓库
+ * @throws SVNException svn异常,例如没有权限等
+ */
+ public SVNRepository getRepository(Pj pj) throws SVNException{
+
+ Usr usr = UsrProvider.getCurrentUsr();
+
+ String svnUrl = parseURL(pj.getUrl());
+ if(StringUtils.isBlank(svnUrl)){
+ throw new RuntimeException(I18N.getLbl("pj.error.url", "URL不可以为空"));
+ }
+ String svnUserName = usr.getUsr();
+ String svnPassword = usr.getPsw();
+ if(!Constants.HTTP_MUTIL.equals(pj.getType())){
+ //pj_usr覆盖用户的密码
+ PjUsr pjUsr = pjUsrDao.get(pj.getPj(), svnUserName);
+ if(pjUsr != null){
+ svnPassword = pjUsr.getPsw();
+ }
+ }
+ svnPassword = EncryptUtil.decrypt(svnPassword);//解密
+
+ SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIDecoded(svnUrl));
+ ISVNAuthenticationManager authManager =
+ SVNWCUtil.createDefaultAuthenticationManager(svnUserName, svnPassword);
+ repository.setAuthenticationManager(authManager);
+
+ return repository;
+ }
+
+ /**
+ * 返回项目仓库的根
+ * @param pj 项目
+ * @return 仓库根
+ */
+ public String getRepositoryRoot(Pj pj){
+ SVNRepository repository = null;
+ try{
+ repository = this.getRepository(pj);
+ return repository.getRepositoryRoot(true).toString();
+ }catch(SVNAuthenticationException e){
+ LOG.error(e.getMessage());
+ return null;
+ } catch (SVNException e) {
+ LOG.error(e.getMessage());
+ e.printStackTrace();
+ return null;
+ }finally{
+ if(repository != null){
+ repository.closeSession();
+ }
+ }
+ }
+
+
+ /**
+ * 获取项目指定路径的svn仓库文件系统
+ * @param pj 项目
+ * @param path 相对仓库根目录的路径
+ * @return 目录或文件系统
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Collection getDir(String pj,String path){
+ if(StringUtils.isBlank(path)){
+ path = "/";//root
+ }
+ if(!path.startsWith("/")){
+ path = "/"+path;
+ }
+ SVNRepository repository = null;
+ try {
+ repository = this.getRepository(pj);
+ SVNProperties properties = new SVNProperties();
+ return repository.getDir(path, SVNRevision.HEAD.getNumber(), properties, (Collection) null);
+ }catch(SVNAuthenticationException e){
+ e.printStackTrace();
+ throw new RuntimeException(I18N.getLbl("svn.auth.error", "认证失败"));
+ }catch (SVNException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.getMessage());
+ }finally{
+ if(repository!=null){
+ repository.closeSession();
+ }
+ }
+ }
+
+ /**
+ * Creates a local blank FSFS-type repository.
+ * A call to this routine is equivalent to
+ * createLocalRepository(path, null, enableRevisionProperties, force)
.
+ *
+ * @param respository a repository root location
+ * @return a local URL (file:///) of a newly
+ * created repository
+ */
+ public static SVNURL createLocalRepository(File respository){
+ try {
+ return SVNRepositoryFactory.createLocalRepository(respository, true,
+ false);
+ } catch (SVNException e) {
+ throw new RuntimeException(I18N.getLbl("pj.save.error.createRepository","创建仓库失败.{0}",new Object[]{respository.getAbsolutePath()})
+ + " : "+ e.getMessage());
+ }
+ }
+
+ static {
+ /*
+ * For using over http:// and https://
+ */
+ DAVRepositoryFactory.setup();
+ /*
+ * For using over svn:// and svn+xxx://
+ */
+ SVNRepositoryFactoryImpl.setup();
+
+ /*
+ * For using over file:///
+ */
+ FSRepositoryFactory.setup();
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/service/SvnService.java b/src/main/java/org/svnadmin/service/SvnService.java
new file mode 100644
index 0000000..98184be
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/SvnService.java
@@ -0,0 +1,620 @@
+package org.svnadmin.service;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Service;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.dao.PjAuthDao;
+import org.svnadmin.dao.PjDao;
+import org.svnadmin.dao.PjGrDao;
+import org.svnadmin.dao.PjGrUsrDao;
+import org.svnadmin.dao.UsrDao;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+import org.svnadmin.entity.PjGrUsr;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.util.EncryptUtil;
+import org.svnadmin.util.I18N;
+
+/**
+ * 导出svn配置信息服务层
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ *
+ */
+@Service(SvnService.BEAN_NAME)
+public class SvnService {
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "svnService";
+
+ /**
+ * 分隔符
+ */
+ private static final String SEP = System.getProperty("line.separator");
+ /**
+ * 日志
+ */
+ private final Logger LOG = Logger.getLogger(this.getClass());
+
+ /**
+ * 项目DAO
+ */
+ @Resource(name = PjDao.BEAN_NAME)
+ protected PjDao pjDao;
+
+ /**
+ * 用户DAO
+ */
+ @Resource(name = UsrDao.BEAN_NAME)
+ protected UsrDao usrDao;
+
+ /**
+ * 项目组DAO
+ */
+ @Resource(name = PjGrDao.BEAN_NAME)
+ protected PjGrDao pjGrDao;
+
+ /**
+ * 项目组用户DAO
+ */
+ @Resource(name = PjGrUsrDao.BEAN_NAME)
+ protected PjGrUsrDao pjGrUsrDao;
+
+ /**
+ * 项目权限DAO
+ */
+ @Resource(name = PjAuthDao.BEAN_NAME)
+ protected PjAuthDao pjAuthDao;
+
+ /**
+ * 导出到配置文件
+ *
+ * @param pj
+ * 项目id
+ */
+ public synchronized void exportConfig(String pj) {
+ this.exportConfig(this.pjDao.get(pj));
+ }
+
+ /**
+ * 导出到配置文件
+ *
+ * @param pj
+ * 项目
+ */
+ public synchronized void exportConfig(Pj pj) {
+ if (pj == null) {
+ return;
+ }
+ File parent = new File(pj.getPath());
+ if (!parent.exists() || !parent.isDirectory()) {
+ throw new RuntimeException(I18N.getLbl("svn.notFoundResp", "找不到仓库 路径{0}",new Object[]{pj.getPath()}));
+ }
+
+ if (Constants.HTTP.equalsIgnoreCase(pj.getType())) {// HTTP(单库) SVNPath
+ this.exportHTTP(pj);
+ } else if (Constants.HTTP_MUTIL.equalsIgnoreCase(pj.getType())) {// HTTP(多库)
+ // SVNParentPath
+ File root = new File(pj.getPath()).getParentFile();
+ this.exportHTTPMutil(root);
+ } else if (Constants.SVN.equalsIgnoreCase(pj.getType())) {// SVN
+ this.exportSVN(pj);
+ }
+
+ }
+
+ /**
+ * 导出svn协议的配置信息
+ *
+ * @param pj
+ * 项目
+ */
+ private void exportSVN(Pj pj) {
+ // 项目的用户
+ List usrList = this.usrDao.getList(pj.getPj());
+ // 项目的用户组
+ Map> pjGrUsrMap = this.getPjGrUsrs(pj.getPj());
+ // 项目的权限
+ Map> pjAuthMap = this.getPjAuths(pj.getPj());
+
+ this.exportSvnConf(pj);
+ this.exportPasswdSVN(pj, usrList);
+ this.exportAuthz(pj, pjGrUsrMap, pjAuthMap);
+ }
+
+ /**
+ * 导出http(单库)的配置信息
+ *
+ * @param pj
+ * 项目
+ */
+ private void exportHTTP(Pj pj) {
+ // 项目的用户
+ List usrList = this.usrDao.getList(pj.getPj());
+ // 项目的用户组
+ Map> pjGrUsrMap = this.getPjGrUsrs(pj.getPj());
+ // 项目的权限
+ Map> pjAuthMap = this.getPjAuths(pj.getPj());
+
+ this.exportSVNPathConf(pj);
+ this.exportPasswdHTTP(pj, usrList);
+ this.exportAuthz(pj, pjGrUsrMap, pjAuthMap);
+ }
+
+ /**
+ * 导出http(多库)的配置信息
+ *
+ * @param root
+ * svn root
+ */
+ private void exportHTTPMutil(File root) {
+ String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/");
+ if (!svnRoot.endsWith("/")) {
+ svnRoot += "/";
+ }
+ // 和这个项目在同一个父目录的所有项目的用户
+ List usrList = this.usrDao.getListByRootPath(svnRoot);
+ // 和这个项目在同一个父目录的所有项目的用户组
+ Map> pjGrUsrMap = this
+ .getPjGrUsrsByRootPath(svnRoot);
+ // 和这个项目在同一个父目录的所有项目的权限
+ Map> pjAuthMap = this
+ .getPjAuthsByRootPath(svnRoot);
+
+ this.exportSVNParentPathConf(root);
+
+ this.exportPasswdHTTPMutil(root, usrList);
+
+ this.exportAuthzHTTPMutil(root, pjGrUsrMap, pjAuthMap);
+ }
+
+ /**
+ * 获取有相同svn root的项目的权限列表
+ *
+ * @param rootPath
+ * svn root
+ * @return 有相同svn root的项目的权限列表
+ */
+ private Map> getPjAuthsByRootPath(String rootPath) {
+ Map> results = new LinkedHashMap>();// >
+ List pjAuthList = this.pjAuthDao.getListByRootPath(rootPath);
+ // 格式化返回数据
+ for (PjAuth pjAuth : pjAuthList) {
+ List authList = results.get(pjAuth.getRes());
+ if (authList == null) {
+ authList = new ArrayList();
+ results.put(pjAuth.getRes(), authList);
+ }
+ authList.add(pjAuth);
+
+ }
+ return results;
+ }
+
+ /**
+ * 获取项目的权限列表
+ *
+ * @param pj
+ * 项目
+ * @return 项目的权限列表
+ */
+ private Map> getPjAuths(String pj) {
+ Map> results = new LinkedHashMap>();// >
+ List pjAuthList = this.pjAuthDao.getList(pj);
+ // 格式化返回数据
+ for (PjAuth pjAuth : pjAuthList) {
+ List authList = results.get(pjAuth.getRes());
+ if (authList == null) {
+ authList = new ArrayList();
+ results.put(pjAuth.getRes(), authList);
+ }
+ authList.add(pjAuth);
+
+ }
+ return results;
+ }
+
+ /**
+ * 获取项目的组列表
+ *
+ * @param pj
+ * 项目
+ * @return 项目的组列表
+ */
+ private Map> getPjGrUsrs(String pj) {
+ Map> results = new LinkedHashMap>();// >
+
+ List pjGrUsrs = this.pjGrUsrDao.getList(pj);
+
+ // 格式化返回数据
+ for (PjGrUsr pjGrUsr : pjGrUsrs) {
+ List grUsrList = results.get(pjGrUsr.getGr());
+ if (grUsrList == null) {
+ grUsrList = new ArrayList();
+ results.put(pjGrUsr.getGr(), grUsrList);
+ }
+ grUsrList.add(pjGrUsr);
+ }
+
+ return results;
+ }
+
+ /**
+ * 获取有相同svn root的项目的权限列表
+ *
+ * @param rootPath
+ * svn root
+ * @return 有相同svn root的项目的权限列表
+ */
+ private Map> getPjGrUsrsByRootPath(String rootPath) {
+
+ Map> results = new LinkedHashMap>();// >
+
+ List pjGrUsrs = this.pjGrUsrDao.getListByRootPath(rootPath);
+
+ // 格式化返回数据
+ for (PjGrUsr pjGrUsr : pjGrUsrs) {
+ String key = pjGrUsr.getPj() + "_" + pjGrUsr.getGr();
+ List grUsrList = results.get(key);// 项目ID_组ID see: Issue 4
+ if (grUsrList == null) {
+ grUsrList = new ArrayList();
+ results.put(key, grUsrList);
+ }
+ grUsrList.add(pjGrUsr);
+ }
+
+ return results;
+
+ }
+
+ /**
+ * 输出http多库方式的密码文件
+ *
+ * @param root
+ * svn root
+ * @param usrList
+ * 所有用户列表
+ */
+ private void exportPasswdHTTPMutil(File root, List usrList) {
+ File outFile = new File(root, "passwd.http");
+ StringBuffer contents = new StringBuffer();
+
+ for (Usr usr : usrList) {
+ // 采用SHA加密
+ // http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ String shaPsw = "{SHA}"
+ + EncryptUtil
+ .encriptSHA1(EncryptUtil.decrypt(usr.getPsw()));
+ contents.append(usr.getUsr()).append(":").append(shaPsw)
+ .append(SEP);
+ }
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 输出http单库方式的密码文件
+ *
+ * @param pj
+ * 项目
+ * @param usrList
+ * 项目用户列表
+ */
+ private void exportPasswdHTTP(Pj pj, List usrList) {
+ File outFile = new File(pj.getPath(), "/conf/passwd.http");
+ StringBuffer contents = new StringBuffer();
+
+ for (Usr usr : usrList) {
+ // 采用SHA加密
+ // http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ String shaPsw = "{SHA}"
+ + EncryptUtil
+ .encriptSHA1(EncryptUtil.decrypt(usr.getPsw()));
+ contents.append(usr.getUsr()).append(":").append(shaPsw)
+ .append(SEP);
+ }
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 输出svn方式的密码文件
+ *
+ * @param pj
+ * 项目
+ * @param usrList
+ * 项目用户列表
+ */
+ private void exportPasswdSVN(Pj pj, List usrList) {
+ File outFile = new File(pj.getPath(), "/conf/passwd");
+ StringBuffer contents = new StringBuffer();
+ contents.append("[users]").append(SEP);
+
+ for (Usr usr : usrList) {
+ contents.append(usr.getUsr()).append("=")
+ .append(EncryptUtil.decrypt(usr.getPsw())).append(SEP);// 解密
+ }
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 输出http多库方式的权限文件
+ *
+ * @param root
+ * svn root
+ * @param pjGrUsrMap
+ * 所有的项目组用户列表
+ * @param resMap
+ * 所有的权限列表
+ */
+ private void exportAuthzHTTPMutil(File root,
+ Map> pjGrUsrMap,
+ Map> resMap) {
+ if (root == null) {
+ return;
+ }
+ File outFile = new File(root, "authz");
+ StringBuffer contents = new StringBuffer();
+ contents.append("[aliases]").append(SEP);
+ contents.append("[groups]").append(SEP);
+
+ for (Iterator grIterator = pjGrUsrMap.keySet().iterator(); grIterator
+ .hasNext();) {
+ String gr = grIterator.next();// 项目ID_组ID see: Issue 4
+ contents.append(gr).append("=");
+ List pjGrUsrList = pjGrUsrMap.get(gr);
+ for (int i = 0; i < pjGrUsrList.size(); i++) {
+ PjGrUsr pjGrUsr = pjGrUsrList.get(i);
+ if (pjGrUsr.getUsr() == null) {
+ continue;
+ }
+ if (i != 0) {
+ contents.append(",");
+ }
+ contents.append(pjGrUsr.getUsr());
+ }
+ contents.append(SEP);
+ }
+
+ contents.append(SEP);
+
+ for (Iterator resIterator = resMap.keySet().iterator(); resIterator
+ .hasNext();) {
+ String res = resIterator.next();
+ contents.append(res).append(SEP);
+ for (PjAuth pjAuth : resMap.get(res)) {
+ if (StringUtils.isNotBlank(pjAuth.getGr())) {
+ // 项目ID_组ID see: Issue 4
+ contents.append("@")
+ .append(pjAuth.getPj() + "_" + pjAuth.getGr())
+ .append("=").append(pjAuth.getRw()).append(SEP);
+ } else if (StringUtils.isNotBlank(pjAuth.getUsr())) {
+ contents.append(pjAuth.getUsr()).append("=")
+ .append(pjAuth.getRw()).append(SEP);
+ }
+ }
+ contents.append(SEP);
+ }
+
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 输出权限配置文件
+ *
+ * @param pj
+ * 项目
+ * @param pjGrUsrMap
+ * 项目的组列表
+ * @param resMap
+ * 项目的权限列表
+ */
+ private void exportAuthz(Pj pj, Map> pjGrUsrMap,
+ Map> resMap) {
+ if (pj == null || StringUtils.isBlank(pj.getPj())) {
+ return;
+ }
+ /*
+ * if(pjGrList == null || pjGrList.size() == 0){ return; } if(pjAuthMap
+ * == null || pjAuthMap.size() == 0){ return; }
+ */
+ File outFile = new File(pj.getPath(), "/conf/authz");
+ StringBuffer contents = new StringBuffer();
+ contents.append("[aliases]").append(SEP);
+ contents.append("[groups]").append(SEP);
+
+ for (Iterator grIterator = pjGrUsrMap.keySet().iterator(); grIterator
+ .hasNext();) {
+ String gr = grIterator.next();
+ contents.append(gr).append("=");
+ List pjGrUsrList = pjGrUsrMap.get(gr);
+ for (int i = 0; i < pjGrUsrList.size(); i++) {
+ PjGrUsr pjGrUsr = pjGrUsrList.get(i);
+ if (pjGrUsr.getUsr() == null) {
+ continue;
+ }
+ if (i != 0) {
+ contents.append(",");
+ }
+ contents.append(pjGrUsr.getUsr());
+ }
+ contents.append(SEP);
+ }
+
+ contents.append(SEP);
+
+ for (Iterator resIterator = resMap.keySet().iterator(); resIterator
+ .hasNext();) {
+ String res = resIterator.next();
+ contents.append(res).append(SEP);
+ for (PjAuth pjAuth : resMap.get(res)) {
+ if (StringUtils.isNotBlank(pjAuth.getGr())) {
+ contents.append("@").append(pjAuth.getGr()).append("=")
+ .append(pjAuth.getRw()).append(SEP);
+ } else if (StringUtils.isNotBlank(pjAuth.getUsr())) {
+ contents.append(pjAuth.getUsr()).append("=")
+ .append(pjAuth.getRw()).append(SEP);
+ }
+ }
+ contents.append(SEP);
+ }
+
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 输出svn方式的svnserve.conf
+ *
+ * @param pj
+ * 项目
+ */
+ private void exportSvnConf(Pj pj) {
+ if (pj == null || StringUtils.isBlank(pj.getPj())) {
+ return;
+ }
+ File outFile = new File(pj.getPath(), "/conf/svnserve.conf");
+
+ StringBuffer contents = new StringBuffer();
+ contents.append("[general]").append(SEP);
+ contents.append("anon-access = none").append(SEP);
+ contents.append("auth-access = write").append(SEP);
+ contents.append("password-db = passwd").append(SEP);
+ contents.append("authz-db = authz").append(SEP);
+ contents.append("[sasl]").append(SEP);
+ this.write(outFile, contents.toString());
+
+ }
+
+ /**
+ * 输出http单库方式的httpd.conf文件
+ *
+ * @param pj
+ * 项目
+ */
+ private void exportSVNPathConf(Pj pj) {
+ if (pj == null || StringUtils.isBlank(pj.getPj())) {
+ return;
+ }
+ File outFile = new File(pj.getPath(), "/conf/httpd.conf");
+ StringBuffer contents = new StringBuffer();
+ contents.append("#Include ").append(pj.getPath())
+ .append("/conf/httpd.conf").append(SEP);
+
+ String location = pj.getPj();
+ // 例如 http://192.168.1.100/svn/projar/trunk
+ if (StringUtils.isNotBlank(pj.getUrl())
+ && pj.getUrl().indexOf("//") != -1) {
+ String svnUrl =RepositoryService.parseURL(pj.getUrl());
+ location = StringUtils.substringAfter(svnUrl, "//");// 192.168.1.100/svn/projar/trunk
+ location = StringUtils.substringAfter(location, "/");// svn/projar/trunk
+ location = StringUtils.substringBeforeLast(location, "/trunk");// svn/projar
+ // see:
+ // Issue
+ // 5
+ }
+
+ contents.append("").append(SEP);
+ contents.append("DAV svn").append(SEP);
+ contents.append("SVNPath ").append(pj.getPath()).append(SEP);
+ contents.append("AuthType Basic").append(SEP);
+ contents.append("AuthName ").append("\"").append(pj.getPj())
+ .append("\"").append(SEP);
+ contents.append("AuthUserFile ").append(pj.getPath())
+ .append("/conf/passwd.http").append(SEP);
+ contents.append("AuthzSVNAccessFile ").append(pj.getPath())
+ .append("/conf/authz").append(SEP);
+ contents.append("Require valid-user").append(SEP);
+ contents.append("").append(SEP);
+ this.write(outFile, contents.toString());
+
+ }
+
+ /**
+ * 输出http多库方式的httpd.conf文件
+ *
+ * @param root
+ * svn root
+ */
+ private void exportSVNParentPathConf(File root) {
+ String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/");
+ File outFile = new File(root, "httpd.conf");
+ StringBuffer contents = new StringBuffer();
+ contents.append("#Include ").append(svnRoot).append("/httpd.conf")
+ .append(SEP);
+
+ String location = root.getName();
+
+ contents.append("")
+ .append(SEP);
+ contents.append("DAV svn").append(SEP);
+ contents.append("SVNListParentPath on").append(SEP);
+ contents.append("SVNParentPath ").append(svnRoot).append(SEP);
+ contents.append("AuthType Basic").append(SEP);
+ contents.append("AuthName ").append("\"")
+ .append("Subversion repositories").append("\"").append(SEP);
+ contents.append("AuthUserFile ").append(svnRoot).append("/passwd.http")
+ .append(SEP);
+ contents.append("AuthzSVNAccessFile ").append(svnRoot).append("/authz")
+ .append(SEP);
+ contents.append("Require valid-user").append(SEP);
+ contents.append("").append(SEP);
+ contents.append("RedirectMatch ^(/").append(location).append(")$ $1/")
+ .append(SEP);
+ this.write(outFile, contents.toString());
+ }
+
+ /**
+ * 写文件流
+ *
+ * @param outFile
+ * 输出文件
+ * @param contents
+ * 内容
+ */
+ private void write(File outFile, String contents) {
+ BufferedWriter writer = null;
+ try {
+ if (contents == null) {
+ contents = "";
+ }
+ if (!outFile.getParentFile().exists()) {
+ outFile.getParentFile().mkdirs();
+ }
+ writer = new BufferedWriter(new OutputStreamWriter(
+ new FileOutputStream(outFile), "UTF-8"));// UTF-8 without
+ // BOM
+ writer.write(contents);
+ LOG.debug(outFile);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.getMessage());
+ } finally {
+ if (writer != null) {
+ try {
+ writer.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/svnadmin/service/UsrService.java b/src/main/java/org/svnadmin/service/UsrService.java
new file mode 100644
index 0000000..d098ff9
--- /dev/null
+++ b/src/main/java/org/svnadmin/service/UsrService.java
@@ -0,0 +1,268 @@
+package org.svnadmin.service;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.svnadmin.common.entity.PageBean;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.dao.PjAuthDao;
+import org.svnadmin.dao.PjDao;
+import org.svnadmin.dao.PjGrUsrDao;
+import org.svnadmin.dao.PjUsrDao;
+import org.svnadmin.dao.UsrDao;
+import org.svnadmin.entity.Pj;
+import org.svnadmin.entity.PjAuth;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.util.EncryptUtil;
+import org.svnadmin.util.I18N;
+
+/**
+ * 用户
+ *
+ * @author Huiwu Yuan
+ * @since 3.0
+ *
+ */
+@Service(UsrService.BEAN_NAME)
+public class UsrService {
+
+ /**
+ * Bean名称
+ */
+ public static final String BEAN_NAME = "usrService";
+
+ /**
+ * 用户DAO
+ */
+ @Resource(name = UsrDao.BEAN_NAME)
+ protected UsrDao usrDao;
+
+ /**
+ * 项目权限DAO
+ */
+ @Resource(name = PjAuthDao.BEAN_NAME)
+ protected PjAuthDao pjAuthDao;
+
+ /**
+ * 项目组用户DAO
+ */
+ @Resource(name = PjGrUsrDao.BEAN_NAME)
+ protected PjGrUsrDao pjGrUsrDao;
+
+ /**
+ * 项目用户DAO
+ */
+ @Resource(name = PjUsrDao.BEAN_NAME)
+ protected PjUsrDao pjUsrDao;
+
+ /**
+ * 项目DAO
+ */
+ @Resource(name = PjDao.BEAN_NAME)
+ protected PjDao pjDao;
+
+ /**
+ * SVN服务层
+ */
+ @Resource(name = SvnService.BEAN_NAME)
+ protected SvnService svnService;
+
+ /**
+ * 获取一个用户
+ *
+ * @param usr
+ * 用户
+ * @return 用户
+ */
+ public Usr get(String usr) {
+ return this.usrDao.get(usr);
+ }
+
+ /**
+ * @return 所有用户列表
+ */
+ public List list() {
+ return this.usrDao.getList();
+ }
+
+ /**
+ * @param pj
+ * 项目
+ * @return 所有项目用户列表(不包括*)
+ */
+ public List list(String pj) {
+ return this.usrDao.getList(pj);
+ }
+
+ /**
+ * 获取这个项目组未选的用户
+ *
+ * @param pj
+ * 项目
+ * @param gr
+ * 组
+ * @return 项目组未选的用户
+ */
+ public List listUnSelected(String pj, String gr) {
+ return this.usrDao.listUnSelected(pj, gr);
+ }
+
+ /**
+ * 删除用户(同时删除项目用户,项目组用户,项目用户权限)
+ *
+ * @param usr
+ * 用户
+ */
+ @Transactional
+ public void delete(String usr) {
+
+ List list = this.getPjList(usr);
+
+ this.pjAuthDao.deleteUsr(usr);
+ this.pjGrUsrDao.deleteUsr(usr);
+ this.pjUsrDao.deleteUsr(usr);
+ this.usrDao.delete(usr);
+
+ // 更新用户所在的项目
+ if (list != null) {
+ for (Pj pj : list) {
+ this.svnService.exportConfig(pj);
+ }
+ }
+ }
+
+ /**
+ * 保存用户
+ *
+ * @param usr
+ * 用户
+ */
+ @Transactional
+ public void save(Usr usr) {
+ if (this.usrDao.get(usr.getUsr()) == null) {
+ this.usrDao.insert(usr);
+ } else {
+ this.usrDao.update(usr);
+ }
+ // 更新用户所在的项目
+ List list = this.getPjList(usr.getUsr());
+ if (list != null) {
+ for (Pj pj : list) {
+ this.svnService.exportConfig(pj);
+ }
+ }
+ }
+
+ /**
+ * @param usr
+ * 用户
+ * @return 用户的项目
+ */
+ public List getPjList(String usr) {
+ List list = this.pjDao.getList(usr);// 用户可以看到的所有项目
+ // 如果项目使用http(多库),只返回一个项目就可以,SvnService导出时,会导出所有相同svn root的项目
+ List results = new ArrayList();
+
+ Map temp = new HashMap();
+ for (Pj pj : list) {
+ if (Constants.HTTP_MUTIL.equals(pj.getType())) {
+ File root = new File(pj.getPath()).getParentFile();// svn root
+ String key = root.getAbsolutePath();
+ if (temp.containsKey(key)) {
+ continue;
+ } else {
+ temp.put(key, pj);
+ results.add(pj);// 第一个
+ }
+ } else {
+ results.add(pj);
+ }
+ }
+
+ return results;
+ }
+
+ /**
+ * @return 总数(不包括*)
+ */
+ public int getCount() {
+ return this.usrDao.getCount();
+ }
+
+ /**
+ * 登录.如果用户表没有数据,表示第一次使用,输入的用户当作是超级管理员。
+ *
+ * @param usr
+ * 用户
+ * @param psw
+ * 密码
+ * @return 成功则返回用户的信息,失败抛出异常
+ */
+ @Transactional
+ public Usr login(String usr, String psw) {
+ int usrCount = this.getCount();
+ if (usrCount == 0) {// 第一次使用,设置管理员
+ Usr entity = new Usr();
+ entity.setUsr(usr);
+ entity.setPsw(EncryptUtil.encrypt(psw));
+ entity.setRole(Constants.USR_ROLE_ADMIN);
+ this.usrDao.insert(entity);
+ // *
+ Usr all = new Usr();
+ all.setUsr("*");
+ all.setPsw("*");
+ this.usrDao.insert(all);
+ //
+ return entity;
+ }
+ // 正常登录
+ Usr entity = this.get(usr);
+ if (entity == null) {
+ throw new RuntimeException(I18N.getLbl("login.error.notfoundusr", "系统不存在用户{0} ",new Object[]{usr}));
+ }
+ if (!entity.getPsw().equals(EncryptUtil.encrypt(psw))) {
+ throw new RuntimeException(I18N.getLbl("login.error.wrongpassword", "用户名或密码有误 "));
+ }
+ return entity;
+ }
+
+ /**
+ * 验证是否连接数据库成功 Issue 12
+ * @throws Exception 验证失败异常
+ */
+ public void validatConnection() throws Exception{
+ this.usrDao.validatConnection();
+ }
+
+ /**
+ * 是否有管理员的权限
+ * @param usr 用户
+ * @return 有管理员权限返回true,否则返回false
+ */
+ public boolean hasAdminRight(Usr usr){
+ if (Constants.USR_ROLE_ADMIN.equals(usr.getRole())) {
+ return true;
+ }
+ return false;
+ }
+ /**
+ * 报表:获取用户所有的权限
+ * @param usr 用户
+ * @return 用户所有的权限
+ */
+ public List getAuths(String usr){
+ return this.pjAuthDao.getByUsr(usr);
+ }
+
+
+ public void queryForPageBean(PageBean pageBean) {
+
+ }
+}
diff --git a/src/main/java/org/svnadmin/servlet/StartupLoddingServlet.java b/src/main/java/org/svnadmin/servlet/StartupLoddingServlet.java
new file mode 100644
index 0000000..f2659bf
--- /dev/null
+++ b/src/main/java/org/svnadmin/servlet/StartupLoddingServlet.java
@@ -0,0 +1,37 @@
+package org.svnadmin.servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.log4j.Logger;
+import org.svnadmin.common.util.HttpUtils;
+import org.svnadmin.common.util.PropUtils;
+
+/**
+ * @author hpboys
+ * @version V1.0
+ * @ClassName: StartupLoddingServlet
+ * @Description: 系统启动时加载数据
+ * @date 2015年6月8日 下午10:19:30
+ */
+@WebServlet(urlPatterns = "/init", loadOnStartup = 2)
+public class StartupLoddingServlet extends HttpServlet {
+
+ private Logger logger = Logger.getLogger(StartupLoddingServlet.class);
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void init() throws ServletException {
+ ServletContext context = getServletContext();
+ String sysPath = PropUtils.get("setting.sys_path");
+ String sysName = HttpUtils.urlDecode(PropUtils.get("setting.sys_name"), "utf-8");
+ context.setAttribute("sysName", sysName);
+ //设置系统应用根目录
+ context.setAttribute("assetsPath", "/" + sysPath + "/assets");
+ context.setAttribute("framePath", "/" + sysPath + "/assets/hui");
+ context.setAttribute("appPath", "/" + sysPath + "/assets/admin");
+ logger.info("load setting finish,the servletContextName is " + context.getServletContextName());
+ }
+}
diff --git a/src/main/java/org/svnadmin/util/EncryptUtil.java b/src/main/java/org/svnadmin/util/EncryptUtil.java
new file mode 100644
index 0000000..cce4458
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/EncryptUtil.java
@@ -0,0 +1,120 @@
+package org.svnadmin.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * 加密工具
+ *
+ * @author Huiwu Yuan
+ * @since 1.0
+ */
+public class EncryptUtil {
+ /**
+ *
+ */
+ private static final String cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "abcdefghijklmnopqrstuvwxyz0123456789#@$";
+
+ /**
+ *
+ */
+ private static final int fillchar = '*';
+
+ /**
+ * 加密
+ *
+ * @param str
+ * 明文
+ * @return 密文
+ */
+ public static String encrypt(String str) {
+ byte[] data = str.getBytes();
+ int c;
+ int len = data.length;
+ StringBuffer ret = new StringBuffer(((len / 3) + 1) * 4);
+ for (int i = 0; i < len; ++i) {
+ c = (data[i] >> 2) & 0x3f;
+ ret.append(cvt.charAt(c));
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 4) & 0x0f;
+ }
+ ret.append(cvt.charAt(c));
+ if (i < len) {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len) {
+ c |= (data[i] >> 6) & 0x03;
+ }
+ ret.append(cvt.charAt(c));
+ } else {
+ ++i;
+ ret.append((char) fillchar);
+ }
+ if (i < len) {
+ c = data[i] & 0x3f;
+ ret.append(cvt.charAt(c));
+ } else {
+ ret.append((char) fillchar);
+ }
+ }
+ return ret.toString();
+ }
+
+ /**
+ * 解密
+ *
+ * @param str
+ * 密文
+ * @return 明文
+ */
+ public static String decrypt(String str) {
+ byte[] data = str.getBytes();
+ int c, c1;
+ int len = data.length;
+ StringBuffer ret = new StringBuffer((len * 3) / 4);
+ for (int i = 0; i < len; ++i) {
+ c = cvt.indexOf(data[i]);
+ ++i;
+ c1 = cvt.indexOf(data[i]);
+ c = ((c << 2) | ((c1 >> 4) & 0x3));
+ ret.append((char) c);
+ if (++i < len) {
+ c = data[i];
+ if (fillchar == c) {
+ break;
+ }
+ c = cvt.indexOf((char) c);
+ c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
+ ret.append((char) c1);
+ }
+ if (++i < len) {
+ c1 = data[i];
+ if (fillchar == c1) {
+ break;
+ }
+ c1 = cvt.indexOf((char) c1);
+ c = ((c << 6) & 0xc0) | c1;
+ ret.append((char) c);
+ }
+ }
+ return ret.toString();
+ }
+
+ /**
+ * apache SHA1 加密
+ *
+ * @param str
+ * 明文
+ * @return 密文
+ */
+ public static String encriptSHA1(String str) {
+ try {
+ return new sun.misc.BASE64Encoder().encode(MessageDigest
+ .getInstance("SHA1").digest(str.getBytes()));
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/org/svnadmin/util/I18N.java b/src/main/java/org/svnadmin/util/I18N.java
new file mode 100644
index 0000000..ddb267f
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/I18N.java
@@ -0,0 +1,171 @@
+/**
+ *
+ */
+package org.svnadmin.util;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.svnadmin.common.util.SpringUtils;
+import org.svnadmin.constant.Constants;
+import org.svnadmin.entity.I18n;
+import org.svnadmin.service.I18nService;
+
+/**
+ * 多语言工具类
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ */
+public class I18N {
+
+ /**
+ * 缓存
+ */
+ private static Map cache = new HashMap();
+ /**
+ * 多语言服务层
+ */
+ private static I18nService i18nService = SpringUtils.getBean(I18nService.BEAN_NAME);
+
+ /**
+ * 获取默认的语言
+ * @param request 请求
+ * @return 获取默认的语言
+ */
+ public static final String getDefaultLang(HttpServletRequest request){
+ //from session
+ String result = (String) request.getSession().getAttribute(Constants.SESSION_KEY_LANG);
+ if(result != null){
+ return result;
+ }
+ //from request local
+ Locale locale = request.getLocale();
+ String country = locale.getCountry();
+ String language = locale.getLanguage();
+
+ if(country.length() != 0 && i18nService.existsLang(language+"_"+country)){//数据库是否存在这个语言?
+ result = language+"_"+country;
+ }
+ if(result == null && i18nService.existsLang(language)){//数据库是否存在这个语言?
+ result = language;
+ }
+ if(result == null){
+ result = Locale.SIMPLIFIED_CHINESE.toString();//default zh_CN
+ getLbl(result, result, Locale.SIMPLIFIED_CHINESE.getDisplayLanguage());//增加当前语言到数据库i18n
+ }
+
+
+ request.getSession().setAttribute(Constants.SESSION_KEY_LANG, result);//set to session
+ return result;
+ }
+
+ /**
+ * @param request 请求
+ * @param id 语言id
+ * @param defValue 默认值
+ * @return 格式化后的多语言
+ */
+ public static final String getLbl(HttpServletRequest request,String id,String defValue){
+ return getLbl(getDefaultLang(request), id, defValue, null);
+ }
+ /**
+ * @param request 请求
+ * @param id 语言id
+ * @param defValue 默认值
+ * @param args 参数
+ * @return 格式化后的多语言
+ */
+ public static final String getLbl(HttpServletRequest request,String id,String defValue,Object[] args){
+ return getLbl(getDefaultLang(request), id, defValue, args);
+ }
+ /**
+ * @param lang 语言
+ * @param id 语言id
+ * @param defValue 默认值
+ * @return 格式化后的多语言
+ */
+ public static final String getLbl(String lang,String id,String defValue){
+ return getLbl(lang, id, defValue, null);
+ }
+ /**
+ * @param lang 语言
+ * @param id key
+ * @param defValue 默认值
+ * @param args 参数
+ * @return 格式化后的多语言
+ */
+ public static final String getLbl(String lang,String id,String defValue,Object[] args){
+ String key = lang+"$"+id;
+ //from cache
+ if(cache.containsKey(key)){
+ return format(cache.get(key), args);
+ }
+ //from database
+ I18n i18n = i18nService.getI18n(lang,id);
+ if(i18n == null){//数据库里不存在
+ i18n = new I18n();
+ i18n.setLang(lang);
+ i18n.setId(id);
+ i18n.setLbl(defValue);
+ i18nService.insert(i18n);
+ }
+
+ cache.put(key, i18n.getLbl());//put into cache
+
+ return format(i18n.getLbl(), args);
+ }
+
+ /**
+ * 格式化消息
+ * @param pattern the pattern for this message format
+ * @param arguments 参数
+ * @return 格式化后的消息
+ */
+ private static String format(String pattern,Object[] arguments){
+// format = new MessageFormat(pattern);
+// format.setLocale(locale);
+// format.applyPattern(pattern);
+// str = format.format(args)
+ if(pattern == null){
+ return "";
+ }
+ return MessageFormat.format(pattern, arguments);
+ }
+
+ /**
+ * 清空缓存
+ */
+ public static synchronized void clearCache(){
+ cache.clear();
+ }
+
+ /**
+ * 提供Service层或DAO使用,会从当前的线程中获取语言
+ * @param id 语言id
+ * @param defValue 默认值
+ * @return 格式化后的多语言
+ *
+ * @see LangProvider
+ */
+ public static final String getLbl(String id,String defValue){
+ return getLbl(LangProvider.getCurrentLang(), id, defValue, null);
+ }
+ /**
+ * 提供Service层或DAO使用,会从当前的线程中获取语言
+ * @param id key
+ * @param defValue 默认值
+ * @param args 参数
+ * @return 格式化后的多语言
+ *
+ * @see LangProvider
+ */
+ public static final String getLbl(String id,String defValue,Object[] args){
+ return getLbl(LangProvider.getCurrentLang(), id, defValue, args);
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/util/LangProvider.java b/src/main/java/org/svnadmin/util/LangProvider.java
new file mode 100644
index 0000000..95164f6
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/LangProvider.java
@@ -0,0 +1,48 @@
+/**
+ *
+ */
+package org.svnadmin.util;
+
+import java.util.Locale;
+
+/**
+ * 为当前的线程提供lang
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public class LangProvider {
+ /**
+ *
+ */
+ private static final ThreadLocal LANG_THREAD_LOCAL = new ThreadLocal();
+
+ /**
+ * @return 当前的语言
+ */
+ public static String getCurrentLang() {
+ String lang = LANG_THREAD_LOCAL.get();
+ if(lang == null){
+// throw new RuntimeException("当前线程没有设置语言!");
+ //默认简体中文
+ return Locale.SIMPLIFIED_CHINESE.toString();
+ }
+ return lang;
+ }
+
+ /**
+ * 设置当前的语言到当前线程中
+ * @param lang 语言
+ */
+ public static void setLang(String lang) {
+ LANG_THREAD_LOCAL.set(lang);
+ }
+
+ /**
+ * 清空线程的语言
+ */
+ public static void removeLang() {
+ LANG_THREAD_LOCAL.remove();
+ }
+}
diff --git a/src/main/java/org/svnadmin/util/SessionUtils.java b/src/main/java/org/svnadmin/util/SessionUtils.java
new file mode 100644
index 0000000..4b8f5c4
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/SessionUtils.java
@@ -0,0 +1,52 @@
+package org.svnadmin.util;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.svnadmin.common.util.SpringUtils;
+import org.svnadmin.constant.SessionConstant;
+import org.svnadmin.entity.Usr;
+import org.svnadmin.service.UsrService;
+
+/**
+ * @描述: Session操作工具类.
+ * @作者: Zoro.
+ * @创建时间: 2016-04-19 17:58.
+ * @版本: 1.0.0.
+ */
+public class SessionUtils {
+
+ /**
+ * 得到当前登录用户
+ * @param session
+ * @return
+ */
+ public static Usr getLogedUser(HttpSession session){
+ Object object = session.getAttribute(SessionConstant.USER_SESSION_KEY);
+ if(object!=null){
+ if(object instanceof Usr){
+ return (Usr)object;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 是否已登录
+ */
+ public static boolean isLogin(HttpServletRequest request) {
+ Usr adminUser = SessionUtils.getLogedUser(request.getSession());
+ return null != adminUser;
+ }
+
+ /**
+ * @param session 请求
+ * @return 当前登录的用户是否有管理员角色
+ * @see org.svnadmin.constant.Constants#USR_ROLE_ADMIN
+ * @see Usr#getRole()
+ */
+ public static boolean hasAdminRight(HttpSession session) {
+ UsrService usrService = SpringUtils.getBean(UsrService.BEAN_NAME);
+ return usrService.hasAdminRight(getLogedUser(session));
+ }
+}
diff --git a/src/main/java/org/svnadmin/util/UsrProvider.java b/src/main/java/org/svnadmin/util/UsrProvider.java
new file mode 100644
index 0000000..ea25742
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/UsrProvider.java
@@ -0,0 +1,46 @@
+/**
+ *
+ */
+package org.svnadmin.util;
+
+import org.svnadmin.entity.Usr;
+
+/**
+ * 为当前的线程提供登录的用户
+ *
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public class UsrProvider {
+ /**
+ *
+ */
+ private static final ThreadLocal USR_THREAD_LOCAL = new ThreadLocal();
+
+ /**
+ * @return 当前的用户
+ */
+ public static Usr getCurrentUsr() {
+ Usr usr = USR_THREAD_LOCAL.get();
+ if(usr == null){
+ throw new RuntimeException("当前线程没有设置用户!");
+ }
+ return usr;
+ }
+
+ /**
+ * 设置当前的用户到当前线程中
+ * @param usr 用户
+ */
+ public static void setUsr(Usr usr) {
+ USR_THREAD_LOCAL.set(usr);
+ }
+
+ /**
+ * 清空线程的用户
+ */
+ public static void removeUsr() {
+ USR_THREAD_LOCAL.remove();
+ }
+}
diff --git a/src/main/java/org/svnadmin/util/filter/ParameterFilter.java b/src/main/java/org/svnadmin/util/filter/ParameterFilter.java
new file mode 100644
index 0000000..ed87b9f
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/filter/ParameterFilter.java
@@ -0,0 +1,48 @@
+package org.svnadmin.util.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.svnadmin.common.util.PrintUtils;
+
+/**
+ * @ClassName: ParameterFilter
+ * @Description: 特殊字符拦截过滤器
+ * @author
+ * @date 2015年7月7日 下午8:24:59
+ * @version V1.0
+ */
+@WebFilter(filterName="ParameterFilter",urlPatterns="/*")
+public class ParameterFilter implements Filter {
+
+ private static Logger logger = Logger.getLogger(ParameterFilter.class);
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest rq = (HttpServletRequest)request;
+ HttpServletResponse rp = (HttpServletResponse)response;
+ if(!rq.getRequestURI().contains(".")){
+ PrintUtils.print(rq);
+ if(rq.getRequestURI().endsWith("/")){
+ rp.sendRedirect("login");
+ return;
+ }
+ }
+ filterChain.doFilter(request, response);
+ }
+
+ public void init(FilterConfig arg0) throws ServletException {}
+
+ public void destroy() {}
+}
+
diff --git a/src/main/java/org/svnadmin/util/interceptor/AdminInterceptor.java b/src/main/java/org/svnadmin/util/interceptor/AdminInterceptor.java
new file mode 100644
index 0000000..84c3658
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/interceptor/AdminInterceptor.java
@@ -0,0 +1,61 @@
+package org.svnadmin.util.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import org.svnadmin.common.annotation.AdminAuthPassport;
+import org.svnadmin.common.annotation.AuthPassport;
+import org.svnadmin.common.util.PropUtils;
+import org.svnadmin.util.SessionUtils;
+
+
+/**
+ * @author hpboys
+ * @version V1.0
+ * @ClassName: AdminInterceptor
+ * @Description: 后台拦截器
+ * @date 2016年4月17日 下午7:17:56
+ */
+public class AdminInterceptor extends HandlerInterceptorAdapter {
+
+ private Logger logger = Logger.getLogger(AdminInterceptor.class);
+
+ private final static String LOGIN_URL = "login";//登录页面
+ private final static String CONSOLE_URL = "pjList";//控制台页面
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ HttpSession session = request.getSession();
+ HandlerMethod auth = (HandlerMethod) handler;
+ AuthPassport authPassport = auth.getMethodAnnotation(AuthPassport.class);
+ if (null != authPassport) {
+ if (SessionUtils.isLogin(request)) {
+ //去控制台页面
+ response.sendRedirect("/" + PropUtils.get("setting.sys_path") + "/" + CONSOLE_URL);
+ return false;
+ }
+ }else{
+ //是否已经登录
+ if (!SessionUtils.isLogin(request)) {
+ //去登录页面
+ response.sendRedirect("/" + PropUtils.get("setting.sys_path") + "/" + LOGIN_URL);
+ return false;
+ }
+ }
+ //鉴权
+ AdminAuthPassport adminAuth = auth.getMethodAnnotation(AdminAuthPassport.class);
+ if(null != adminAuth){
+ if(!SessionUtils.hasAdminRight(session)){
+ //无权限页面
+ request.getRequestDispatcher("/WEB-INF/views/common/not_auth.jsp").forward(request,response);
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/svnadmin/util/place/SystemPropertyPlaceholderConfigurer.java b/src/main/java/org/svnadmin/util/place/SystemPropertyPlaceholderConfigurer.java
new file mode 100644
index 0000000..c74e5d4
--- /dev/null
+++ b/src/main/java/org/svnadmin/util/place/SystemPropertyPlaceholderConfigurer.java
@@ -0,0 +1,23 @@
+package org.svnadmin.util.place;
+
+import java.util.Properties;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.svnadmin.common.util.PropUtils;
+
+/**
+ * @ClassName: SystemPropertyPlaceholderConfigurer
+ * @Description: 系统配置文件的属性加载
+ * @author zyj
+ * @date 2015年9月17日 下午1:55:39
+ * @version V1.0
+ */
+public class SystemPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
+
+ protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
+ PropUtils.initConfigProperties(props);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/tree/entity/Tree.java b/src/main/java/org/tree/entity/Tree.java
new file mode 100644
index 0000000..3e8858b
--- /dev/null
+++ b/src/main/java/org/tree/entity/Tree.java
@@ -0,0 +1,109 @@
+package org.tree.entity;
+
+import java.io.Serializable;
+
+
+/**
+ * 树
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public class Tree implements Serializable{
+ /**
+ * 序列化ID
+ */
+ private static final long serialVersionUID = -785319127620330061L;
+ /**
+ * ID
+ */
+ private String id;
+ /**
+ * 父节点ID
+ */
+ private String parentId;
+ /**
+ * 是否是叶子
+ */
+ private boolean leaf;
+ /**
+ * 节点服务层
+ */
+ private String treeNodeService;
+
+ /**
+ * 默认构造函数
+ */
+ public Tree() {
+ }
+
+ /**
+ * 构造函数
+ * @param id ID
+ * @param parentId 父节点ID
+ * @param treeNodeService 节点服务层
+ */
+ public Tree(String id,String parentId,String treeNodeService){
+ this.id=id;
+ this.parentId=parentId;
+ this.treeNodeService = treeNodeService;
+ }
+
+ /**
+ * @return ID
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * @param id ID
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * @return 父节点ID
+ */
+ public String getParentId() {
+ return parentId;
+ }
+
+ /**
+ * @param parentId 父节点ID
+ */
+ public void setParentId(String parentId) {
+ this.parentId = parentId;
+ }
+
+ /**
+ * @return 是否是叶子
+ */
+ public boolean isLeaf() {
+ return leaf;
+ }
+
+ /**
+ * @param leaf 是否是叶子
+ */
+ public void setLeaf(boolean leaf) {
+ this.leaf = leaf;
+ }
+
+ /**
+ * @return 节点服务层
+ */
+ public String getTreeNodeService() {
+ return treeNodeService;
+ }
+
+ /**
+ * @param treeNodeService 节点服务层
+ */
+ public void setTreeNodeService(String treeNodeService) {
+ this.treeNodeService = treeNodeService;
+ }
+
+
+}
diff --git a/src/main/java/org/tree/entity/TreeNode.java b/src/main/java/org/tree/entity/TreeNode.java
new file mode 100644
index 0000000..97c64bf
--- /dev/null
+++ b/src/main/java/org/tree/entity/TreeNode.java
@@ -0,0 +1,217 @@
+package org.tree.entity;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+/**
+ * 树节点
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public class TreeNode implements Comparable,Serializable{
+ /**
+ * 序列化ID
+ */
+ private static final long serialVersionUID = -2006855434442859723L;
+ /**
+ * 节点显示的文字
+ */
+ private String text;
+ /**
+ * 点击节点时的url链接
+ */
+ private String url;
+ /**
+ * 是否是叶子
+ */
+ private boolean leaf;
+ /**
+ * 父节点
+ */
+ private TreeNode parent;
+
+ /**
+ * 叶子
+ */
+ private List children;
+
+
+ /**
+ * 参数
+ */
+ private Map parameters;
+ /**
+ * 属性
+ */
+ private Map attributes;
+
+ /**
+ * 默认构造函数
+ */
+ public TreeNode() {
+ }
+
+ /**
+ * 构造函数
+ * @param text 节点显示的文字
+ */
+ public TreeNode(String text){
+ this.text=text;
+ }
+
+ /**
+ * @return 父节点
+ */
+ public TreeNode getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent 父节点
+ */
+ public void setParent(TreeNode parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return 叶子
+ */
+ public List getChildren() {
+ return children;
+ }
+
+ /**
+ * @param children 叶子
+ */
+ public void setChildren(List children) {
+ if(children !=null){
+ for (TreeNode treeNode : children) {
+ treeNode.setParent(this);
+ }
+ }
+ this.children = children;
+ }
+
+ /**
+ * @return 是否是叶子
+ */
+ public boolean isLeaf() {
+ return leaf;
+ }
+
+ /**
+ * @param leaf 是否是叶子
+ */
+ public void setLeaf(boolean leaf) {
+ this.leaf = leaf;
+ }
+
+ /**
+ * @return 参数
+ */
+ public Map getParameters() {
+ return parameters;
+ }
+
+ /**
+ * @param parameters 参数
+ */
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * @return 属性
+ */
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * @param attributes 属性
+ */
+ public void setAttributes(Map attributes) {
+ this.attributes = attributes;
+ }
+
+ /**
+ * 增加一个参数
+ * @param key 键
+ * @param value 值
+ */
+ public void addParamete(String key,String value){
+ if(parameters == null){
+ parameters = new HashMap();
+ }
+ parameters.put(key, value);
+ }
+
+ /**
+ * 增加一个属性
+ * @param key 键
+ * @param value 值
+ */
+ public void addAttribute(String key,String value){
+ if(attributes == null){
+ attributes = new HashMap();
+ }
+ attributes.put(key, value);
+ }
+
+ /**
+ * @return 节点显示的文字
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @param text 节点显示的文字
+ */
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ /**
+ * @return 点击节点时的url链接
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * @param url 点击节点时的url链接
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public int compareTo(TreeNode o) {
+ if(this.isLeaf()){
+ if(o.isLeaf()){
+ if(this.getText() == null){
+ return -1;
+ }else{
+ return this.getText().compareToIgnoreCase(o.getText());
+ }
+ }else{
+ return 1;
+ }
+ }else{
+ if(o.isLeaf()){
+ return -1;
+ }else{
+ if(this.getText() == null){
+ return -1;
+ }else{
+ return this.getText().compareToIgnoreCase(o.getText());
+ }
+ }
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/org/tree/service/AbstractTreeNodeService.java b/src/main/java/org/tree/service/AbstractTreeNodeService.java
new file mode 100644
index 0000000..6dfb380
--- /dev/null
+++ b/src/main/java/org/tree/service/AbstractTreeNodeService.java
@@ -0,0 +1,192 @@
+package org.tree.service;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.tree.entity.Tree;
+import org.tree.entity.TreeNode;
+
+
+/**
+ * 抽象树节点服务层
+ * @author Huiwu Yuan
+ * @since 3.0.2
+ *
+ */
+public abstract class AbstractTreeNodeService implements TreeNodeService {
+
+ public StringBuffer getHTML(Tree tree, Map parameters) {
+ StringBuffer html = new StringBuffer();
+ List nodes = getTreeNodes(tree, parameters);
+ if (nodes == null || nodes.size() == 0) {
+ return null;
+ }
+ html.append("");
+ for (int i = 0; nodes != null && i < nodes.size(); i++) {
+ TreeNode treeNode = nodes.get(i);
+
+ // htmlsrc
+ html.append("- allParam = new HashMap();
+ if (parameters != null) {
+ allParam.putAll(parameters);
+ }
+ Map treeNodeParameters = treeNode.getParameters();
+ if (treeNodeParameters != null) {
+ allParam.putAll(treeNodeParameters);
+ }
+ allParam.remove(TreeService.TREE_ID_VAR);
+ allParam.remove(TreeService.TREE_PARENTID_VAR);
+ prepareParameters(html, allParam);
+
+ // url
+ if (treeNode.getUrl() != null) {
+ this.prepareAttribute(html, "url", treeNode.getUrl());
+ }
+
+ // otherAttributes
+ Map attributes = treeNode.getAttributes();
+ if (attributes != null) {
+ Iterator attributeKeys = treeNode.getAttributes()
+ .keySet().iterator();
+ while (attributeKeys.hasNext()) {
+ String att = attributeKeys.next();
+ prepareAttribute(html, att, treeNode.getAttributes().get(
+ att));
+ }
+ }
+ // end otherAttributes
+
+ // end