Bladeren bron

初始化

sunlightcs 7 jaren geleden
commit
79c08d7c53
100 gewijzigde bestanden met toevoegingen van 7401 en 0 verwijderingen
  1. 339 0
      LICENSE
  2. 1 0
      README.md
  3. 330 0
      doc/db.sql
  4. 195 0
      pom.xml
  5. 14 0
      src/main/java/io/renren/RenrenApplication.java
  6. 22 0
      src/main/java/io/renren/common/annotation/SysLog.java
  7. 78 0
      src/main/java/io/renren/common/aspect/SysLogAspect.java
  8. 55 0
      src/main/java/io/renren/common/exception/RRException.java
  9. 51 0
      src/main/java/io/renren/common/exception/RRExceptionHandler.java
  10. 14 0
      src/main/java/io/renren/common/utils/ConfigConstant.java
  11. 102 0
      src/main/java/io/renren/common/utils/Constant.java
  12. 30 0
      src/main/java/io/renren/common/utils/DateUtils.java
  13. 13 0
      src/main/java/io/renren/common/utils/HttpContextUtils.java
  14. 58 0
      src/main/java/io/renren/common/utils/IPUtils.java
  15. 81 0
      src/main/java/io/renren/common/utils/PageUtils.java
  16. 55 0
      src/main/java/io/renren/common/utils/Query.java
  17. 57 0
      src/main/java/io/renren/common/utils/R.java
  18. 45 0
      src/main/java/io/renren/common/utils/SpringContextUtils.java
  19. 25 0
      src/main/java/io/renren/common/validator/Assert.java
  20. 40 0
      src/main/java/io/renren/common/validator/ValidatorUtils.java
  21. 10 0
      src/main/java/io/renren/common/validator/group/AddGroup.java
  22. 10 0
      src/main/java/io/renren/common/validator/group/AliyunGroup.java
  23. 14 0
      src/main/java/io/renren/common/validator/group/Group.java
  24. 10 0
      src/main/java/io/renren/common/validator/group/QcloudGroup.java
  25. 10 0
      src/main/java/io/renren/common/validator/group/QiniuGroup.java
  26. 12 0
      src/main/java/io/renren/common/validator/group/UpdateGroup.java
  27. 530 0
      src/main/java/io/renren/common/xss/HTMLFilter.java
  28. 43 0
      src/main/java/io/renren/common/xss/SQLFilter.java
  29. 30 0
      src/main/java/io/renren/common/xss/XssFilter.java
  30. 140 0
      src/main/java/io/renren/common/xss/XssHttpServletRequestWrapper.java
  31. 158 0
      src/main/java/io/renren/config/DruidConfig.java
  32. 43 0
      src/main/java/io/renren/config/FilterConfig.java
  33. 103 0
      src/main/java/io/renren/config/ShiroConfig.java
  34. 55 0
      src/main/java/io/renren/modules/job/config/ScheduleConfig.java
  35. 133 0
      src/main/java/io/renren/modules/job/controller/ScheduleJobController.java
  36. 56 0
      src/main/java/io/renren/modules/job/controller/ScheduleJobLogController.java
  37. 23 0
      src/main/java/io/renren/modules/job/dao/ScheduleJobDao.java
  38. 17 0
      src/main/java/io/renren/modules/job/dao/ScheduleJobLogDao.java
  39. 161 0
      src/main/java/io/renren/modules/job/entity/ScheduleJobEntity.java
  40. 133 0
      src/main/java/io/renren/modules/job/entity/ScheduleJobLogEntity.java
  41. 37 0
      src/main/java/io/renren/modules/job/service/ScheduleJobLogService.java
  42. 66 0
      src/main/java/io/renren/modules/job/service/ScheduleJobService.java
  43. 38 0
      src/main/java/io/renren/modules/job/service/impl/ScheduleJobLogServiceImpl.java
  44. 126 0
      src/main/java/io/renren/modules/job/service/impl/ScheduleJobServiceImpl.java
  45. 46 0
      src/main/java/io/renren/modules/job/task/TestTask.java
  46. 81 0
      src/main/java/io/renren/modules/job/utils/ScheduleJob.java
  47. 47 0
      src/main/java/io/renren/modules/job/utils/ScheduleRunnable.java
  48. 151 0
      src/main/java/io/renren/modules/job/utils/ScheduleUtils.java
  49. 55 0
      src/main/java/io/renren/modules/oss/cloud/AliyunCloudStorageService.java
  50. 234 0
      src/main/java/io/renren/modules/oss/cloud/CloudStorageConfig.java
  51. 68 0
      src/main/java/io/renren/modules/oss/cloud/CloudStorageService.java
  52. 36 0
      src/main/java/io/renren/modules/oss/cloud/OSSFactory.java
  53. 81 0
      src/main/java/io/renren/modules/oss/cloud/QcloudCloudStorageService.java
  54. 70 0
      src/main/java/io/renren/modules/oss/cloud/QiniuCloudStorageService.java
  55. 136 0
      src/main/java/io/renren/modules/oss/controller/SysOssController.java
  56. 17 0
      src/main/java/io/renren/modules/oss/dao/SysOssDao.java
  57. 61 0
      src/main/java/io/renren/modules/oss/entity/SysOssEntity.java
  58. 30 0
      src/main/java/io/renren/modules/oss/service/SysOssService.java
  59. 55 0
      src/main/java/io/renren/modules/oss/service/impl/SysOssServiceImpl.java
  60. 25 0
      src/main/java/io/renren/modules/sys/controller/AbstractController.java
  61. 98 0
      src/main/java/io/renren/modules/sys/controller/SysConfigController.java
  62. 48 0
      src/main/java/io/renren/modules/sys/controller/SysLogController.java
  63. 56 0
      src/main/java/io/renren/modules/sys/controller/SysLoginController.java
  64. 203 0
      src/main/java/io/renren/modules/sys/controller/SysMenuController.java
  65. 129 0
      src/main/java/io/renren/modules/sys/controller/SysRoleController.java
  66. 154 0
      src/main/java/io/renren/modules/sys/controller/SysUserController.java
  67. 42 0
      src/main/java/io/renren/modules/sys/dao/BaseDao.java
  68. 27 0
      src/main/java/io/renren/modules/sys/dao/SysConfigDao.java
  69. 16 0
      src/main/java/io/renren/modules/sys/dao/SysLogDao.java
  70. 33 0
      src/main/java/io/renren/modules/sys/dao/SysMenuDao.java
  71. 22 0
      src/main/java/io/renren/modules/sys/dao/SysRoleDao.java
  72. 22 0
      src/main/java/io/renren/modules/sys/dao/SysRoleMenuDao.java
  73. 39 0
      src/main/java/io/renren/modules/sys/dao/SysUserDao.java
  74. 22 0
      src/main/java/io/renren/modules/sys/dao/SysUserRoleDao.java
  75. 20 0
      src/main/java/io/renren/modules/sys/dao/SysUserTokenDao.java
  76. 45 0
      src/main/java/io/renren/modules/sys/entity/SysConfigEntity.java
  77. 115 0
      src/main/java/io/renren/modules/sys/entity/SysLogEntity.java
  78. 196 0
      src/main/java/io/renren/modules/sys/entity/SysMenuEntity.java
  79. 120 0
      src/main/java/io/renren/modules/sys/entity/SysRoleEntity.java
  80. 76 0
      src/main/java/io/renren/modules/sys/entity/SysRoleMenuEntity.java
  81. 211 0
      src/main/java/io/renren/modules/sys/entity/SysUserEntity.java
  82. 76 0
      src/main/java/io/renren/modules/sys/entity/SysUserRoleEntity.java
  83. 70 0
      src/main/java/io/renren/modules/sys/entity/SysUserTokenEntity.java
  84. 92 0
      src/main/java/io/renren/modules/sys/oauth2/OAuth2Filter.java
  85. 73 0
      src/main/java/io/renren/modules/sys/oauth2/OAuth2Realm.java
  86. 29 0
      src/main/java/io/renren/modules/sys/oauth2/OAuth2Token.java
  87. 46 0
      src/main/java/io/renren/modules/sys/oauth2/TokenGenerator.java
  88. 27 0
      src/main/java/io/renren/modules/sys/service/ShiroService.java
  89. 63 0
      src/main/java/io/renren/modules/sys/service/SysConfigService.java
  90. 30 0
      src/main/java/io/renren/modules/sys/service/SysLogService.java
  91. 69 0
      src/main/java/io/renren/modules/sys/service/SysMenuService.java
  92. 23 0
      src/main/java/io/renren/modules/sys/service/SysRoleMenuService.java
  93. 34 0
      src/main/java/io/renren/modules/sys/service/SysRoleService.java
  94. 24 0
      src/main/java/io/renren/modules/sys/service/SysUserRoleService.java
  95. 73 0
      src/main/java/io/renren/modules/sys/service/SysUserService.java
  96. 29 0
      src/main/java/io/renren/modules/sys/service/SysUserTokenService.java
  97. 60 0
      src/main/java/io/renren/modules/sys/service/impl/ShiroServiceImpl.java
  98. 79 0
      src/main/java/io/renren/modules/sys/service/impl/SysConfigServiceImpl.java
  99. 54 0
      src/main/java/io/renren/modules/sys/service/impl/SysLogServiceImpl.java
  100. 0 0
      src/main/java/io/renren/modules/sys/service/impl/SysMenuServiceImpl.java

+ 339 - 0
LICENSE

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., [http://fsf.org/]
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    {description}
+    Copyright (C) 2017  独孤求胜
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  {signature of Ty Coon}, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 1 - 0
README.md

@@ -0,0 +1 @@
+#renren-jeecms

File diff suppressed because it is too large
+ 330 - 0
doc/db.sql


+ 195 - 0
pom.xml

@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>io.renren</groupId>
+	<artifactId>renren-fast</artifactId>
+	<version>1.0.0</version>
+	<packaging>jar</packaging>
+	<description>renren-fast</description>
+
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>1.5.3.RELEASE</version>
+	</parent>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<java.version>1.8</java.version>
+		<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
+		<mysql.version>5.1.38</mysql.version>
+		<druid.version>1.0.28</druid.version>
+		<quartz.version>2.3.0</quartz.version>
+		<swagger.version>2.6.1</swagger.version>
+		<commons.lang.version>2.6</commons.lang.version>
+		<commons.fileupload.version>1.3.1</commons.fileupload.version>
+		<commons.io.version>2.5</commons.io.version>
+		<commons.codec.version>1.10</commons.codec.version>
+		<commons.configuration.version>1.10</commons.configuration.version>
+		<shiro.version>1.3.2</shiro.version>
+		<qiniu.version>[7.2.0, 7.2.99]</qiniu.version>
+		<aliyun.oss.version>2.5.0</aliyun.oss.version>
+		<qcloud.cos.version>4.4</qcloud.cos.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-configuration-processor</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.mybatis.spring.boot</groupId>
+			<artifactId>mybatis-spring-boot-starter</artifactId>
+			<version>${mybatis.spring.boot.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>${mysql.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid</artifactId>
+			<version>${druid.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.quartz-scheduler</groupId>
+			<artifactId>quartz</artifactId>
+			<version>${quartz.version}</version>
+			<exclusions>
+				<exclusion>
+					<groupId>com.mchange</groupId>
+					<artifactId>c3p0</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>io.springfox</groupId>
+			<artifactId>springfox-swagger2</artifactId>
+			<version>${swagger.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>io.springfox</groupId>
+			<artifactId>springfox-swagger-ui</artifactId>
+			<version>${swagger.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>${commons.lang.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-fileupload</groupId>
+			<artifactId>commons-fileupload</artifactId>
+			<version>${commons.fileupload.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>${commons.io.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>${commons.codec.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-configuration</groupId>
+			<artifactId>commons-configuration</artifactId>
+			<version>${commons.configuration.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.shiro</groupId>
+			<artifactId>shiro-core</artifactId>
+			<version>${shiro.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.shiro</groupId>
+			<artifactId>shiro-spring</artifactId>
+			<version>${shiro.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.qiniu</groupId>
+			<artifactId>qiniu-java-sdk</artifactId>
+			<version>${qiniu.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.aliyun.oss</groupId>
+			<artifactId>aliyun-sdk-oss</artifactId>
+			<version>${aliyun.oss.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.qcloud</groupId>
+			<artifactId>cos_api</artifactId>
+			<version>${qcloud.cos.version}</version>
+			<exclusions>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-log4j12</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<fork>true</fork>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<repositories>
+		<repository>
+			<id>public</id>
+			<name>aliyun nexus</name>
+			<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+		</repository>
+	</repositories>
+	<pluginRepositories>
+		<pluginRepository>
+			<id>public</id>
+			<name>aliyun nexus</name>
+			<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+
+</project>

+ 14 - 0
src/main/java/io/renren/RenrenApplication.java

@@ -0,0 +1,14 @@
+package io.renren;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+
+@SpringBootApplication
+public class RenrenApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(RenrenApplication.class, args);
+	}
+
+}

+ 22 - 0
src/main/java/io/renren/common/annotation/SysLog.java

@@ -0,0 +1,22 @@
+package io.renren.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 系统日志注解
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017年3月8日 上午10:19:56
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SysLog {
+
+	String value() default "";
+}

+ 78 - 0
src/main/java/io/renren/common/aspect/SysLogAspect.java

@@ -0,0 +1,78 @@
+package io.renren.common.aspect;
+
+import com.google.gson.Gson;
+import io.renren.modules.sys.entity.SysLogEntity;
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.service.SysLogService;
+import io.renren.common.utils.HttpContextUtils;
+import io.renren.common.utils.IPUtils;
+import io.renren.common.annotation.SysLog;
+import org.apache.shiro.SecurityUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Date;
+
+
+/**
+ * 系统日志,切面处理类
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017年3月8日 上午11:07:35
+ */
+@Aspect
+@Component
+public class SysLogAspect {
+	@Autowired
+	private SysLogService sysLogService;
+	
+	@Pointcut("@annotation(io.renren.common.annotation.SysLog)")
+	public void logPointCut() { 
+		
+	}
+	
+	@Before("logPointCut()")
+	public void saveSysLog(JoinPoint joinPoint) {
+		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+		Method method = signature.getMethod();
+		
+		SysLogEntity sysLog = new SysLogEntity();
+		SysLog syslog = method.getAnnotation(SysLog.class);
+		if(syslog != null){
+			//注解上的描述 
+			sysLog.setOperation(syslog.value());
+		}
+		
+		//请求的方法名
+		String className = joinPoint.getTarget().getClass().getName();
+		String methodName = signature.getName();
+		sysLog.setMethod(className + "." + methodName + "()");
+		
+		//请求的参数
+		Object[] args = joinPoint.getArgs();
+		String params = new Gson().toJson(args[0]);
+		sysLog.setParams(params);
+		
+		//获取request
+		HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
+		//设置IP地址
+		sysLog.setIp(IPUtils.getIpAddr(request));
+		
+		//用户名
+		String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
+		sysLog.setUsername(username);
+		
+		sysLog.setCreateDate(new Date());
+		//保存系统日志
+		sysLogService.save(sysLog);
+	}
+	
+}

+ 55 - 0
src/main/java/io/renren/common/exception/RRException.java

@@ -0,0 +1,55 @@
+package io.renren.common.exception;
+
+/**
+ * 自定义异常
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年10月27日 下午10:11:27
+ */
+public class RRException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+	
+    private String msg;
+    private int code = 500;
+    
+    public RRException(String msg) {
+		super(msg);
+		this.msg = msg;
+	}
+	
+	public RRException(String msg, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+	}
+	
+	public RRException(String msg, int code) {
+		super(msg);
+		this.msg = msg;
+		this.code = code;
+	}
+	
+	public RRException(String msg, int code, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+		this.code = code;
+	}
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public void setCode(int code) {
+		this.code = code;
+	}
+	
+	
+}

+ 51 - 0
src/main/java/io/renren/common/exception/RRExceptionHandler.java

@@ -0,0 +1,51 @@
+package io.renren.common.exception;
+
+import io.renren.common.utils.R;
+import org.apache.shiro.authz.AuthorizationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * 异常处理器
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年10月27日 下午10:16:19
+ */
+@RestControllerAdvice
+public class RRExceptionHandler {
+	private Logger logger = LoggerFactory.getLogger(getClass());
+
+	/**
+	 * 自定义异常
+	 */
+	@ExceptionHandler(RRException.class)
+	public R handleRRException(RRException e){
+		R r = new R();
+		r.put("code", e.getCode());
+		r.put("msg", e.getMessage());
+
+		return r;
+	}
+
+	@ExceptionHandler(DuplicateKeyException.class)
+	public R handleDuplicateKeyException(DuplicateKeyException e){
+		logger.error(e.getMessage(), e);
+		return R.error("数据库中已存在该记录");
+	}
+
+	@ExceptionHandler(AuthorizationException.class)
+	public R handleAuthorizationException(AuthorizationException e){
+		logger.error(e.getMessage(), e);
+		return R.error("没有权限,请联系管理员授权");
+	}
+
+	@ExceptionHandler(Exception.class)
+	public R handleException(Exception e){
+		logger.error(e.getMessage(), e);
+		return R.error();
+	}
+}

+ 14 - 0
src/main/java/io/renren/common/utils/ConfigConstant.java

@@ -0,0 +1,14 @@
+package io.renren.common.utils;
+
+/**
+ * 系统参数相关Key
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-26 10:33
+ */
+public class ConfigConstant {
+    /**
+     * 云存储配置KEY
+     */
+    public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY";
+}

+ 102 - 0
src/main/java/io/renren/common/utils/Constant.java

@@ -0,0 +1,102 @@
+package io.renren.common.utils;
+
+/**
+ * 常量
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月15日 下午1:23:52
+ */
+public class Constant {
+	/** 超级管理员ID */
+	public static final int SUPER_ADMIN = 1;
+
+	/**
+	 * 菜单类型
+	 * 
+	 * @author chenshun
+	 * @email sunlightcs@gmail.com
+	 * @date 2016年11月15日 下午1:24:29
+	 */
+    public enum MenuType {
+        /**
+         * 目录
+         */
+    	CATALOG(0),
+        /**
+         * 菜单
+         */
+        MENU(1),
+        /**
+         * 按钮
+         */
+        BUTTON(2);
+
+        private int value;
+
+        private MenuType(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+    
+    /**
+     * 定时任务状态
+     * 
+     * @author chenshun
+     * @email sunlightcs@gmail.com
+     * @date 2016年12月3日 上午12:07:22
+     */
+    public enum ScheduleStatus {
+        /**
+         * 正常
+         */
+    	NORMAL(0),
+        /**
+         * 暂停
+         */
+    	PAUSE(1);
+
+        private int value;
+
+        private ScheduleStatus(int value) {
+            this.value = value;
+        }
+        
+        public int getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * 云服务商
+     */
+    public enum CloudService {
+        /**
+         * 七牛云
+         */
+        QINIU(1),
+        /**
+         * 阿里云
+         */
+        ALIYUN(2),
+        /**
+         * 腾讯云
+         */
+        QCLOUD(3);
+
+        private int value;
+
+        private CloudService(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+}

+ 30 - 0
src/main/java/io/renren/common/utils/DateUtils.java

@@ -0,0 +1,30 @@
+package io.renren.common.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 日期处理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月21日 下午12:53:33
+ */
+public class DateUtils {
+	/** 时间格式(yyyy-MM-dd) */
+	public final static String DATE_PATTERN = "yyyy-MM-dd";
+	/** 时间格式(yyyy-MM-dd HH:mm:ss) */
+	public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+	
+	public static String format(Date date) {
+        return format(date, DATE_PATTERN);
+    }
+
+    public static String format(Date date, String pattern) {
+        if(date != null){
+            SimpleDateFormat df = new SimpleDateFormat(pattern);
+            return df.format(date);
+        }
+        return null;
+    }
+}

+ 13 - 0
src/main/java/io/renren/common/utils/HttpContextUtils.java

@@ -0,0 +1,13 @@
+package io.renren.common.utils;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class HttpContextUtils {
+
+	public static HttpServletRequest getHttpServletRequest() {
+		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+	}
+}

+ 58 - 0
src/main/java/io/renren/common/utils/IPUtils.java

@@ -0,0 +1,58 @@
+package io.renren.common.utils;
+
+import com.alibaba.druid.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * IP地址
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017年3月8日 下午12:57:02
+ */
+public class IPUtils {
+	private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
+
+	/**
+	 * 获取IP地址
+	 * 
+	 * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
+	 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
+	 */
+	public static String getIpAddr(HttpServletRequest request) {
+    	String ip = null;
+        try {
+            ip = request.getHeader("x-forwarded-for");
+            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("Proxy-Client-IP");
+            }
+            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("WL-Proxy-Client-IP");
+            }
+            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_CLIENT_IP");
+            }
+            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+            }
+            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
+                ip = request.getRemoteAddr();
+            }
+        } catch (Exception e) {
+        	logger.error("IPUtils ERROR ", e);
+        }
+        
+//        //使用代理,则获取第一个IP地址
+//        if(StringUtils.isEmpty(ip) && ip.length() > 15) {
+//			if(ip.indexOf(",") > 0) {
+//				ip = ip.substring(0, ip.indexOf(","));
+//			}
+//		}
+        
+        return ip;
+    }
+	
+}

+ 81 - 0
src/main/java/io/renren/common/utils/PageUtils.java

@@ -0,0 +1,81 @@
+package io.renren.common.utils;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页工具类
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月4日 下午12:59:00
+ */
+public class PageUtils implements Serializable {
+	private static final long serialVersionUID = 1L;
+	//总记录数
+	private int totalCount;
+	//每页记录数
+	private int pageSize;
+	//总页数
+	private int totalPage;
+	//当前页数
+	private int currPage;
+	//列表数据
+	private List<?> list;
+	
+	/**
+	 * 分页
+	 * @param list        列表数据
+	 * @param totalCount  总记录数
+	 * @param pageSize    每页记录数
+	 * @param currPage    当前页数
+	 */
+	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
+		this.list = list;
+		this.totalCount = totalCount;
+		this.pageSize = pageSize;
+		this.currPage = currPage;
+		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
+	}
+
+	public int getTotalCount() {
+		return totalCount;
+	}
+
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+
+	public int getPageSize() {
+		return pageSize;
+	}
+
+	public void setPageSize(int pageSize) {
+		this.pageSize = pageSize;
+	}
+
+	public int getTotalPage() {
+		return totalPage;
+	}
+
+	public void setTotalPage(int totalPage) {
+		this.totalPage = totalPage;
+	}
+
+	public int getCurrPage() {
+		return currPage;
+	}
+
+	public void setCurrPage(int currPage) {
+		this.currPage = currPage;
+	}
+
+	public List<?> getList() {
+		return list;
+	}
+
+	public void setList(List<?> list) {
+		this.list = list;
+	}
+	
+}

+ 55 - 0
src/main/java/io/renren/common/utils/Query.java

@@ -0,0 +1,55 @@
+package io.renren.common.utils;
+
+import io.renren.common.xss.SQLFilter;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 查询参数
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-14 23:15
+ */
+public class Query extends LinkedHashMap<String, Object> {
+	private static final long serialVersionUID = 1L;
+	//当前页码
+    private int page;
+    //每页条数
+    private int limit;
+
+    public Query(Map<String, Object> params){
+        this.putAll(params);
+
+        //分页参数
+        this.page = Integer.parseInt(params.get("page").toString());
+        this.limit = Integer.parseInt(params.get("limit").toString());
+        this.put("offset", (page - 1) * limit);
+        this.put("page", page);
+        this.put("limit", limit);
+
+        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
+        String sidx = params.get("sidx").toString();
+        String order = params.get("order").toString();
+        this.put("sidx", SQLFilter.sqlInject(sidx));
+        this.put("order", SQLFilter.sqlInject(order));
+    }
+
+
+    public int getPage() {
+        return page;
+    }
+
+    public void setPage(int page) {
+        this.page = page;
+    }
+
+    public int getLimit() {
+        return limit;
+    }
+
+    public void setLimit(int limit) {
+        this.limit = limit;
+    }
+}

+ 57 - 0
src/main/java/io/renren/common/utils/R.java

@@ -0,0 +1,57 @@
+package io.renren.common.utils;
+
+import org.apache.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 返回数据
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年10月27日 下午9:59:27
+ */
+public class R extends HashMap<String, Object> {
+	private static final long serialVersionUID = 1L;
+	
+	public R() {
+		put("code", 0);
+	}
+	
+	public static R error() {
+		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
+	}
+	
+	public static R error(String msg) {
+		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
+	}
+	
+	public static R error(int code, String msg) {
+		R r = new R();
+		r.put("code", code);
+		r.put("msg", msg);
+		return r;
+	}
+
+	public static R ok(String msg) {
+		R r = new R();
+		r.put("msg", msg);
+		return r;
+	}
+	
+	public static R ok(Map<String, Object> map) {
+		R r = new R();
+		r.putAll(map);
+		return r;
+	}
+	
+	public static R ok() {
+		return new R();
+	}
+
+	public R put(String key, Object value) {
+		super.put(key, value);
+		return this;
+	}
+}

+ 45 - 0
src/main/java/io/renren/common/utils/SpringContextUtils.java

@@ -0,0 +1,45 @@
+package io.renren.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Spring Context 工具类
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月29日 下午11:45:51
+ */
+@Component
+public class SpringContextUtils implements ApplicationContextAware {
+	public static ApplicationContext applicationContext; 
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext)
+			throws BeansException {
+		SpringContextUtils.applicationContext = applicationContext;
+	}
+
+	public static Object getBean(String name) {
+		return applicationContext.getBean(name);
+	}
+
+	public static <T> T getBean(String name, Class<T> requiredType) {
+		return applicationContext.getBean(name, requiredType);
+	}
+
+	public static boolean containsBean(String name) {
+		return applicationContext.containsBean(name);
+	}
+
+	public static boolean isSingleton(String name) {
+		return applicationContext.isSingleton(name);
+	}
+
+	public static Class<? extends Object> getType(String name) {
+		return applicationContext.getType(name);
+	}
+
+}

+ 25 - 0
src/main/java/io/renren/common/validator/Assert.java

@@ -0,0 +1,25 @@
+package io.renren.common.validator;
+
+import io.renren.common.exception.RRException;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * 数据校验
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-23 15:50
+ */
+public abstract class Assert {
+
+    public static void isBlank(String str, String message) {
+        if (StringUtils.isBlank(str)) {
+            throw new RRException(message);
+        }
+    }
+
+    public static void isNull(Object object, String message) {
+        if (object == null) {
+            throw new RRException(message);
+        }
+    }
+}

+ 40 - 0
src/main/java/io/renren/common/validator/ValidatorUtils.java

@@ -0,0 +1,40 @@
+package io.renren.common.validator;
+
+import io.renren.common.exception.RRException;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.util.Set;
+
+/**
+ * hibernate-validator校验工具类
+ *
+ * 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-15 10:50
+ */
+public class ValidatorUtils {
+    private static Validator validator;
+
+    static {
+        validator = Validation.buildDefaultValidatorFactory().getValidator();
+    }
+
+    /**
+     * 校验对象
+     * @param object        待校验对象
+     * @param groups        待校验的组
+     * @throws RRException  校验不通过,则报RRException异常
+     */
+    public static void validateEntity(Object object, Class<?>... groups)
+            throws RRException {
+        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
+        if (!constraintViolations.isEmpty()) {
+        	ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next();
+            throw new RRException(constraint.getMessage());
+        }
+    }
+}

+ 10 - 0
src/main/java/io/renren/common/validator/group/AddGroup.java

@@ -0,0 +1,10 @@
+package io.renren.common.validator.group;
+
+/**
+ * 新增数据 Group
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-16 0:04
+ */
+public interface AddGroup {
+}

+ 10 - 0
src/main/java/io/renren/common/validator/group/AliyunGroup.java

@@ -0,0 +1,10 @@
+package io.renren.common.validator.group;
+
+/**
+ * 阿里云
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-28 13:51
+ */
+public interface AliyunGroup {
+}

+ 14 - 0
src/main/java/io/renren/common/validator/group/Group.java

@@ -0,0 +1,14 @@
+package io.renren.common.validator.group;
+
+import javax.validation.GroupSequence;
+
+/**
+ * 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-15 23:15
+ */
+@GroupSequence({AddGroup.class, UpdateGroup.class})
+public interface Group {
+
+}

+ 10 - 0
src/main/java/io/renren/common/validator/group/QcloudGroup.java

@@ -0,0 +1,10 @@
+package io.renren.common.validator.group;
+
+/**
+ * 腾讯云
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-28 13:51
+ */
+public interface QcloudGroup {
+}

+ 10 - 0
src/main/java/io/renren/common/validator/group/QiniuGroup.java

@@ -0,0 +1,10 @@
+package io.renren.common.validator.group;
+
+/**
+ * 七牛
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-28 13:51
+ */
+public interface QiniuGroup {
+}

+ 12 - 0
src/main/java/io/renren/common/validator/group/UpdateGroup.java

@@ -0,0 +1,12 @@
+package io.renren.common.validator.group;
+
+/**
+ * 更新数据 Group
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-15 21:21
+ */
+
+public interface UpdateGroup {
+
+}

+ 530 - 0
src/main/java/io/renren/common/xss/HTMLFilter.java

@@ -0,0 +1,530 @@
+package io.renren.common.xss;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * HTML filtering utility for protecting against XSS (Cross Site Scripting).
+ *
+ * This code is licensed LGPLv3
+ *
+ * This code is a Java port of the original work in PHP by Cal Hendersen.
+ * http://code.iamcal.com/php/lib_filter/
+ *
+ * The trickiest part of the translation was handling the differences in regex handling
+ * between PHP and Java.  These resources were helpful in the process:
+ *
+ * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
+ * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
+ * http://www.regular-expressions.info/modifiers.html
+ *
+ * A note on naming conventions: instance variables are prefixed with a "v"; global
+ * constants are in all caps.
+ *
+ * Sample use:
+ * String input = ...
+ * String clean = new HTMLFilter().filter( input );
+ *
+ * The class is not thread safe. Create a new instance if in doubt.
+ *
+ * If you find bugs or have suggestions on improvement (especially regarding
+ * performance), please contact us.  The latest version of this
+ * source, and our contact details, can be found at http://xss-html-filter.sf.net
+ *
+ * @author Joseph O'Connell
+ * @author Cal Hendersen
+ * @author Michael Semb Wever
+ */
+public final class HTMLFilter {
+
+    /** regex flag union representing /si modifiers in php **/
+    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
+    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
+    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
+    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
+    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
+    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
+    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
+    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
+    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
+    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
+    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
+    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
+    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
+    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
+    private static final Pattern P_END_ARROW = Pattern.compile("^>");
+    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_AMP = Pattern.compile("&");
+    private static final Pattern P_QUOTE = Pattern.compile("<");
+    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
+    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
+    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
+
+    // @xxx could grow large... maybe use sesat's ReferenceMap
+    private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
+    private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
+
+    /** set of allowed html elements, along with allowed attributes for each element **/
+    private final Map<String, List<String>> vAllowed;
+    /** counts of open tags for each (allowable) html element **/
+    private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
+
+    /** html elements which must always be self-closing (e.g. "<img />") **/
+    private final String[] vSelfClosingTags;
+    /** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/
+    private final String[] vNeedClosingTags;
+    /** set of disallowed html elements **/
+    private final String[] vDisallowed;
+    /** attributes which should be checked for valid protocols **/
+    private final String[] vProtocolAtts;
+    /** allowed protocols **/
+    private final String[] vAllowedProtocols;
+    /** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/
+    private final String[] vRemoveBlanks;
+    /** entities allowed within html markup **/
+    private final String[] vAllowedEntities;
+    /** flag determining whether comments are allowed in input String. */
+    private final boolean stripComment;
+    private final boolean encodeQuotes;
+    private boolean vDebug = false;
+    /**
+     * flag determining whether to try to make tags when presented with "unbalanced"
+     * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>").  If set to false,
+     * unbalanced angle brackets will be html escaped.
+     */
+    private final boolean alwaysMakeTags;
+
+    /** Default constructor.
+     *
+     */
+    public HTMLFilter() {
+        vAllowed = new HashMap<>();
+
+        final ArrayList<String> a_atts = new ArrayList<String>();
+        a_atts.add("href");
+        a_atts.add("target");
+        vAllowed.put("a", a_atts);
+
+        final ArrayList<String> img_atts = new ArrayList<String>();
+        img_atts.add("src");
+        img_atts.add("width");
+        img_atts.add("height");
+        img_atts.add("alt");
+        vAllowed.put("img", img_atts);
+
+        final ArrayList<String> no_atts = new ArrayList<String>();
+        vAllowed.put("b", no_atts);
+        vAllowed.put("strong", no_atts);
+        vAllowed.put("i", no_atts);
+        vAllowed.put("em", no_atts);
+
+        vSelfClosingTags = new String[]{"img"};
+        vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
+        vDisallowed = new String[]{};
+        vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
+        vProtocolAtts = new String[]{"src", "href"};
+        vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
+        vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
+        stripComment = true;
+        encodeQuotes = true;
+        alwaysMakeTags = true;
+    }
+
+    /** Set debug flag to true. Otherwise use default settings. See the default constructor.
+     *
+     * @param debug turn debug on with a true argument
+     */
+    public HTMLFilter(final boolean debug) {
+        this();
+        vDebug = debug;
+
+    }
+
+    /** Map-parameter configurable constructor.
+     *
+     * @param conf map containing configuration. keys match field names.
+     */
+    public HTMLFilter(final Map<String,Object> conf) {
+
+        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
+        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
+        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
+        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
+        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
+        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
+        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
+        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
+
+        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
+        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
+        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
+        vDisallowed = (String[]) conf.get("vDisallowed");
+        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
+        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
+        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
+        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
+        stripComment =  conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
+        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
+        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
+    }
+
+    private void reset() {
+        vTagCounts.clear();
+    }
+
+    private void debug(final String msg) {
+        if (vDebug) {
+            Logger.getAnonymousLogger().info(msg);
+        }
+    }
+
+    //---------------------------------------------------------------
+    // my versions of some PHP library functions
+    public static String chr(final int decimal) {
+        return String.valueOf((char) decimal);
+    }
+
+    public static String htmlSpecialChars(final String s) {
+        String result = s;
+        result = regexReplace(P_AMP, "&amp;", result);
+        result = regexReplace(P_QUOTE, "&quot;", result);
+        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
+        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
+        return result;
+    }
+
+    //---------------------------------------------------------------
+    /**
+     * given a user submitted input String, filter out any invalid or restricted
+     * html.
+     *
+     * @param input text (i.e. submitted by a user) than may contain html
+     * @return "clean" version of input, with only valid, whitelisted html elements allowed
+     */
+    public String filter(final String input) {
+        reset();
+        String s = input;
+
+        debug("************************************************");
+        debug("              INPUT: " + input);
+
+        s = escapeComments(s);
+        debug("     escapeComments: " + s);
+
+        s = balanceHTML(s);
+        debug("        balanceHTML: " + s);
+
+        s = checkTags(s);
+        debug("          checkTags: " + s);
+
+        s = processRemoveBlanks(s);
+        debug("processRemoveBlanks: " + s);
+
+        s = validateEntities(s);
+        debug("    validateEntites: " + s);
+
+        debug("************************************************\n\n");
+        return s;
+    }
+
+    public boolean isAlwaysMakeTags(){
+        return alwaysMakeTags;
+    }
+
+    public boolean isStripComments(){
+        return stripComment;
+    }
+
+    private String escapeComments(final String s) {
+        final Matcher m = P_COMMENTS.matcher(s);
+        final StringBuffer buf = new StringBuffer();
+        if (m.find()) {
+            final String match = m.group(1); //(.*?)
+            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
+        }
+        m.appendTail(buf);
+
+        return buf.toString();
+    }
+
+    private String balanceHTML(String s) {
+        if (alwaysMakeTags) {
+            //
+            // try and form html
+            //
+            s = regexReplace(P_END_ARROW, "", s);
+            s = regexReplace(P_BODY_TO_END, "<$1>", s);
+            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
+
+        } else {
+            //
+            // escape stray brackets
+            //
+            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
+            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
+
+            //
+            // the last regexp causes '<>' entities to appear
+            // (we need to do a lookahead assertion so that the last bracket can
+            // be used in the next pass of the regexp)
+            //
+            s = regexReplace(P_BOTH_ARROWS, "", s);
+        }
+
+        return s;
+    }
+
+    private String checkTags(String s) {
+        Matcher m = P_TAGS.matcher(s);
+
+        final StringBuffer buf = new StringBuffer();
+        while (m.find()) {
+            String replaceStr = m.group(1);
+            replaceStr = processTag(replaceStr);
+            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
+        }
+        m.appendTail(buf);
+
+        s = buf.toString();
+
+        // these get tallied in processTag
+        // (remember to reset before subsequent calls to filter method)
+        for (String key : vTagCounts.keySet()) {
+            for (int ii = 0; ii < vTagCounts.get(key); ii++) {
+                s += "</" + key + ">";
+            }
+        }
+
+        return s;
+    }
+
+    private String processRemoveBlanks(final String s) {
+        String result = s;
+        for (String tag : vRemoveBlanks) {
+            if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
+                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
+            }
+            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
+            if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
+                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
+            }
+            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
+        }
+
+        return result;
+    }
+
+    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
+        Matcher m = regex_pattern.matcher(s);
+        return m.replaceAll(replacement);
+    }
+
+    private String processTag(final String s) {
+        // ending tags
+        Matcher m = P_END_TAG.matcher(s);
+        if (m.find()) {
+            final String name = m.group(1).toLowerCase();
+            if (allowed(name)) {
+                if (!inArray(name, vSelfClosingTags)) {
+                    if (vTagCounts.containsKey(name)) {
+                        vTagCounts.put(name, vTagCounts.get(name) - 1);
+                        return "</" + name + ">";
+                    }
+                }
+            }
+        }
+
+        // starting tags
+        m = P_START_TAG.matcher(s);
+        if (m.find()) {
+            final String name = m.group(1).toLowerCase();
+            final String body = m.group(2);
+            String ending = m.group(3);
+
+            //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
+            if (allowed(name)) {
+                String params = "";
+
+                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
+                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
+                final List<String> paramNames = new ArrayList<String>();
+                final List<String> paramValues = new ArrayList<String>();
+                while (m2.find()) {
+                    paramNames.add(m2.group(1)); //([a-z0-9]+)
+                    paramValues.add(m2.group(3)); //(.*?)
+                }
+                while (m3.find()) {
+                    paramNames.add(m3.group(1)); //([a-z0-9]+)
+                    paramValues.add(m3.group(3)); //([^\"\\s']+)
+                }
+
+                String paramName, paramValue;
+                for (int ii = 0; ii < paramNames.size(); ii++) {
+                    paramName = paramNames.get(ii).toLowerCase();
+                    paramValue = paramValues.get(ii);
+
+//          debug( "paramName='" + paramName + "'" );
+//          debug( "paramValue='" + paramValue + "'" );
+//          debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
+
+                    if (allowedAttribute(name, paramName)) {
+                        if (inArray(paramName, vProtocolAtts)) {
+                            paramValue = processParamProtocol(paramValue);
+                        }
+                        params += " " + paramName + "=\"" + paramValue + "\"";
+                    }
+                }
+
+                if (inArray(name, vSelfClosingTags)) {
+                    ending = " /";
+                }
+
+                if (inArray(name, vNeedClosingTags)) {
+                    ending = "";
+                }
+
+                if (ending == null || ending.length() < 1) {
+                    if (vTagCounts.containsKey(name)) {
+                        vTagCounts.put(name, vTagCounts.get(name) + 1);
+                    } else {
+                        vTagCounts.put(name, 1);
+                    }
+                } else {
+                    ending = " /";
+                }
+                return "<" + name + params + ending + ">";
+            } else {
+                return "";
+            }
+        }
+
+        // comments
+        m = P_COMMENT.matcher(s);
+        if (!stripComment && m.find()) {
+            return  "<" + m.group() + ">";
+        }
+
+        return "";
+    }
+
+    private String processParamProtocol(String s) {
+        s = decodeEntities(s);
+        final Matcher m = P_PROTOCOL.matcher(s);
+        if (m.find()) {
+            final String protocol = m.group(1);
+            if (!inArray(protocol, vAllowedProtocols)) {
+                // bad protocol, turn into local anchor link instead
+                s = "#" + s.substring(protocol.length() + 1, s.length());
+                if (s.startsWith("#//")) {
+                    s = "#" + s.substring(3, s.length());
+                }
+            }
+        }
+
+        return s;
+    }
+
+    private String decodeEntities(String s) {
+        StringBuffer buf = new StringBuffer();
+
+        Matcher m = P_ENTITY.matcher(s);
+        while (m.find()) {
+            final String match = m.group(1);
+            final int decimal = Integer.decode(match).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENTITY_UNICODE.matcher(s);
+        while (m.find()) {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENCODE.matcher(s);
+        while (m.find()) {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        s = validateEntities(s);
+        return s;
+    }
+
+    private String validateEntities(final String s) {
+        StringBuffer buf = new StringBuffer();
+
+        // validate entities throughout the string
+        Matcher m = P_VALID_ENTITIES.matcher(s);
+        while (m.find()) {
+            final String one = m.group(1); //([^&;]*)
+            final String two = m.group(2); //(?=(;|&|$))
+            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
+        }
+        m.appendTail(buf);
+
+        return encodeQuotes(buf.toString());
+    }
+
+    private String encodeQuotes(final String s){
+        if(encodeQuotes){
+            StringBuffer buf = new StringBuffer();
+            Matcher m = P_VALID_QUOTES.matcher(s);
+            while (m.find()) {
+                final String one = m.group(1); //(>|^)
+                final String two = m.group(2); //([^<]+?)
+                final String three = m.group(3); //(<|$)
+                m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
+            }
+            m.appendTail(buf);
+            return buf.toString();
+        }else{
+            return s;
+        }
+    }
+
+    private String checkEntity(final String preamble, final String term) {
+
+        return ";".equals(term) && isValidEntity(preamble)
+                ? '&' + preamble
+                : "&amp;" + preamble;
+    }
+
+    private boolean isValidEntity(final String entity) {
+        return inArray(entity, vAllowedEntities);
+    }
+
+    private static boolean inArray(final String s, final String[] array) {
+        for (String item : array) {
+            if (item != null && item.equals(s)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean allowed(final String name) {
+        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
+    }
+
+    private boolean allowedAttribute(final String name, final String paramName) {
+        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
+    }
+}

+ 43 - 0
src/main/java/io/renren/common/xss/SQLFilter.java

@@ -0,0 +1,43 @@
+package io.renren.common.xss;
+
+import io.renren.common.exception.RRException;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * SQL过滤
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-01 16:16
+ */
+public class SQLFilter {
+
+    /**
+     * SQL注入过滤
+     * @param str  待验证的字符串
+     */
+    public static String sqlInject(String str){
+        if(StringUtils.isBlank(str)){
+            return null;
+        }
+        //去掉'|"|;|\字符
+        str = StringUtils.replace(str, "'", "");
+        str = StringUtils.replace(str, "\"", "");
+        str = StringUtils.replace(str, ";", "");
+        str = StringUtils.replace(str, "\\", "");
+
+        //转换成小写
+        str = str.toLowerCase();
+
+        //非法字符
+        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};
+
+        //判断是否包含非法字符
+        for(String keyword : keywords){
+            if(str.indexOf(keyword) != -1){
+                throw new RRException("包含非法字符");
+            }
+        }
+
+        return str;
+    }
+}

+ 30 - 0
src/main/java/io/renren/common/xss/XssFilter.java

@@ -0,0 +1,30 @@
+package io.renren.common.xss;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * XSS过滤
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-01 10:20
+ */
+public class XssFilter implements Filter {
+
+	@Override
+	public void init(FilterConfig config) throws ServletException {
+	}
+
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
+		XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
+				(HttpServletRequest) request);
+		chain.doFilter(xssRequest, response);
+	}
+
+	@Override
+	public void destroy() {
+	}
+
+}

+ 140 - 0
src/main/java/io/renren/common/xss/XssHttpServletRequestWrapper.java

@@ -0,0 +1,140 @@
+package io.renren.common.xss;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * XSS过滤处理
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-01 11:29
+ */
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
+    //没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
+    HttpServletRequest orgRequest;
+    //html过滤
+    private final static HTMLFilter htmlFilter = new HTMLFilter();
+
+    public XssHttpServletRequestWrapper(HttpServletRequest request) {
+        super(request);
+        orgRequest = request;
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        //非json类型,直接返回
+        if(!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)){
+            return super.getInputStream();
+        }
+
+        //为空,直接返回
+        String json = IOUtils.toString(super.getInputStream(), "utf-8");
+        if (StringUtils.isBlank(json)) {
+            return super.getInputStream();
+        }
+
+        //xss过滤
+        json = xssEncode(json);
+        final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
+        return new ServletInputStream() {
+            @Override
+            public boolean isFinished() {
+                return true;
+            }
+
+            @Override
+            public boolean isReady() {
+                return true;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+
+            }
+
+            @Override
+            public int read() throws IOException {
+                return bis.read();
+            }
+        };
+    }
+
+    @Override
+    public String getParameter(String name) {
+        String value = super.getParameter(xssEncode(name));
+        if (StringUtils.isNotBlank(value)) {
+            value = xssEncode(value);
+        }
+        return value;
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        String[] parameters = super.getParameterValues(name);
+        if (parameters == null || parameters.length == 0) {
+            return null;
+        }
+
+        for (int i = 0; i < parameters.length; i++) {
+            parameters[i] = xssEncode(parameters[i]);
+        }
+        return parameters;
+    }
+
+    @Override
+    public Map<String,String[]> getParameterMap() {
+        Map<String,String[]> map = new LinkedHashMap<>();
+        Map<String,String[]> parameters = super.getParameterMap();
+        for (String key : parameters.keySet()) {
+            String[] values = parameters.get(key);
+            for (int i = 0; i < values.length; i++) {
+                values[i] = xssEncode(values[i]);
+            }
+            map.put(key, values);
+        }
+        return map;
+    }
+
+    @Override
+    public String getHeader(String name) {
+        String value = super.getHeader(xssEncode(name));
+        if (StringUtils.isNotBlank(value)) {
+            value = xssEncode(value);
+        }
+        return value;
+    }
+
+    private String xssEncode(String input) {
+        return htmlFilter.filter(input);
+    }
+
+    /**
+     * 获取最原始的request
+     */
+    public HttpServletRequest getOrgRequest() {
+        return orgRequest;
+    }
+
+    /**
+     * 获取最原始的request
+     */
+    public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
+        if (request instanceof XssHttpServletRequestWrapper) {
+            return ((XssHttpServletRequestWrapper) request).getOrgRequest();
+        }
+
+        return request;
+    }
+
+}

+ 158 - 0
src/main/java/io/renren/config/DruidConfig.java

@@ -0,0 +1,158 @@
+package io.renren.config;
+
+import com.alibaba.druid.filter.Filter;
+import com.alibaba.druid.filter.stat.StatFilter;
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.support.http.StatViewServlet;
+import com.alibaba.druid.wall.WallConfig;
+import com.alibaba.druid.wall.WallFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Druid配置
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-21 0:00
+ */
+@Configuration
+public class DruidConfig {
+    private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
+
+    @Value("${spring.datasource.url:#{null}}")
+    private String dbUrl;
+    @Value("${spring.datasource.username: #{null}}")
+    private String username;
+    @Value("${spring.datasource.password:#{null}}")
+    private String password;
+    @Value("${spring.datasource.driverClassName:#{null}}")
+    private String driverClassName;
+    @Value("${spring.datasource.initialSize:#{null}}")
+    private Integer initialSize;
+    @Value("${spring.datasource.minIdle:#{null}}")
+    private Integer minIdle;
+    @Value("${spring.datasource.maxActive:#{null}}")
+    private Integer maxActive;
+    @Value("${spring.datasource.maxWait:#{null}}")
+    private Integer maxWait;
+    @Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
+    private Integer timeBetweenEvictionRunsMillis;
+    @Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
+    private Integer minEvictableIdleTimeMillis;
+    @Value("${spring.datasource.validationQuery:#{null}}")
+    private String validationQuery;
+    @Value("${spring.datasource.testWhileIdle:#{null}}")
+    private Boolean testWhileIdle;
+    @Value("${spring.datasource.testOnBorrow:#{null}}")
+    private Boolean testOnBorrow;
+    @Value("${spring.datasource.testOnReturn:#{null}}")
+    private Boolean testOnReturn;
+    @Value("${spring.datasource.poolPreparedStatements:#{null}}")
+    private Boolean poolPreparedStatements;
+    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
+    private Integer maxPoolPreparedStatementPerConnectionSize;
+    @Value("${spring.datasource.filters:#{null}}")
+    private String filters;
+    @Value("{spring.datasource.connectionProperties:#{null}}")
+    private String connectionProperties;
+
+    @Bean
+    @Primary
+    public DataSource dataSource(){
+        DruidDataSource datasource = new DruidDataSource();
+
+        datasource.setUrl(this.dbUrl);
+        datasource.setUsername(username);
+        datasource.setPassword(password);
+        datasource.setDriverClassName(driverClassName);
+        //configuration
+        if(initialSize != null) {
+            datasource.setInitialSize(initialSize);
+        }
+        if(minIdle != null) {
+            datasource.setMinIdle(minIdle);
+        }
+        if(maxActive != null) {
+            datasource.setMaxActive(maxActive);
+        }
+        if(maxWait != null) {
+            datasource.setMaxWait(maxWait);
+        }
+        if(timeBetweenEvictionRunsMillis != null) {
+            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+        }
+        if(minEvictableIdleTimeMillis != null) {
+            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+        }
+        if(validationQuery!=null) {
+            datasource.setValidationQuery(validationQuery);
+        }
+        if(testWhileIdle != null) {
+            datasource.setTestWhileIdle(testWhileIdle);
+        }
+        if(testOnBorrow != null) {
+            datasource.setTestOnBorrow(testOnBorrow);
+        }
+        if(testOnReturn != null) {
+            datasource.setTestOnReturn(testOnReturn);
+        }
+        if(poolPreparedStatements != null) {
+            datasource.setPoolPreparedStatements(poolPreparedStatements);
+        }
+        if(maxPoolPreparedStatementPerConnectionSize != null) {
+            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
+        }
+
+        if(connectionProperties != null) {
+            datasource.setConnectionProperties(connectionProperties);
+        }
+
+        List<Filter> filters = new ArrayList<>();
+        filters.add(statFilter());
+        filters.add(wallFilter());
+        datasource.setProxyFilters(filters);
+
+        return datasource;
+    }
+
+    @Bean
+    public ServletRegistrationBean druidServlet() {
+        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
+        servletRegistrationBean.setServlet(new StatViewServlet());
+        servletRegistrationBean.addUrlMappings("/druid/*");
+        return servletRegistrationBean;
+    }
+
+    @Bean
+    public StatFilter statFilter(){
+        StatFilter statFilter = new StatFilter();
+        statFilter.setLogSlowSql(true);
+        statFilter.setMergeSql(true);
+        statFilter.setSlowSqlMillis(1000);
+
+        return statFilter;
+    }
+
+    @Bean
+    public WallFilter wallFilter(){
+        WallFilter wallFilter = new WallFilter();
+
+        //允许执行多条SQL
+        WallConfig config = new WallConfig();
+        config.setMultiStatementAllow(true);
+        wallFilter.setConfig(config);
+
+        return wallFilter;
+    }
+
+}

+ 43 - 0
src/main/java/io/renren/config/FilterConfig.java

@@ -0,0 +1,43 @@
+package io.renren.config;
+
+import io.renren.common.xss.XssFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.DispatcherType;
+
+/**
+ * Filter配置
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-21 21:56
+ */
+@Configuration
+public class FilterConfig {
+
+    @Bean
+    public FilterRegistrationBean shiroFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
+        //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
+        registration.addInitParameter("targetFilterLifecycle", "true");
+        registration.setEnabled(true);
+        registration.setOrder(Integer.MAX_VALUE - 1);
+        registration.addUrlPatterns("/*");
+        return registration;
+    }
+
+    @Bean
+    public FilterRegistrationBean xssFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new XssFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("xssFilter");
+        registration.setOrder(Integer.MAX_VALUE);
+        return registration;
+    }
+}

+ 103 - 0
src/main/java/io/renren/config/ShiroConfig.java

@@ -0,0 +1,103 @@
+package io.renren.config;
+
+import io.renren.modules.sys.oauth2.OAuth2Filter;
+import io.renren.modules.sys.oauth2.OAuth2Realm;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Shiro配置
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-20 18:33
+ */
+@Configuration
+public class ShiroConfig {
+
+    @Bean("sessionManager")
+    public SessionManager sessionManager(){
+        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+        //设置session过期时间为1分钟(单位:毫秒),默认为30分钟
+//        sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
+//        sessionManager.setSessionValidationSchedulerEnabled(true);
+//        sessionManager.setSessionIdUrlRewritingEnabled(false);
+        sessionManager.setSessionIdCookieEnabled(false);
+        return sessionManager;
+    }
+
+    @Bean("securityManager")
+    public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        securityManager.setRealm(oAuth2Realm);
+        securityManager.setSessionManager(sessionManager);
+
+        return securityManager;
+    }
+
+    @Bean("shiroFilter")
+    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
+        shiroFilter.setSecurityManager(securityManager);
+
+        //oauth过滤
+        Map<String, Filter> filters = new HashMap<>();
+        filters.put("oauth2", new OAuth2Filter());
+        shiroFilter.setFilters(filters);
+
+        Map<String, String> filterMap = new LinkedHashMap<>();
+        filterMap.put("/webjars/**", "anon");
+        filterMap.put("/druid/**", "anon");
+
+        //swagger配置
+        filterMap.put("/swagger**", "anon");
+        filterMap.put("/v2/api-docs", "anon");
+        filterMap.put("/swagger-resources/configuration/ui", "anon");
+
+        filterMap.put("/sys/login", "anon");
+        filterMap.put("/**/*.css", "anon");
+        filterMap.put("/**/*.js", "anon");
+        filterMap.put("/**/*.html", "anon");
+        filterMap.put("/fonts/**", "anon");
+        filterMap.put("/plugins/**", "anon");
+        filterMap.put("/favicon.ico", "anon");
+        filterMap.put("/", "anon");
+        filterMap.put("/**", "oauth2");
+        shiroFilter.setFilterChainDefinitionMap(filterMap);
+
+        return shiroFilter;
+    }
+
+    @Bean("lifecycleBeanPostProcessor")
+    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
+        return new LifecycleBeanPostProcessor();
+    }
+
+    @Bean
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
+        proxyCreator.setProxyTargetClass(true);
+        return proxyCreator;
+    }
+
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+        advisor.setSecurityManager(securityManager);
+        return advisor;
+    }
+
+}

+ 55 - 0
src/main/java/io/renren/modules/job/config/ScheduleConfig.java

@@ -0,0 +1,55 @@
+package io.renren.modules.job.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+
+import javax.sql.DataSource;
+import java.util.Properties;
+
+/**
+ * 定时任务配置
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-04-20 23:38
+ */
+@Configuration
+public class ScheduleConfig {
+
+    @Bean
+    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
+        SchedulerFactoryBean factory = new SchedulerFactoryBean();
+        factory.setDataSource(dataSource);
+
+        //quartz参数
+        Properties prop = new Properties();
+        prop.put("org.quartz.scheduler.instanceName", "RenrenScheduler");
+        prop.put("org.quartz.scheduler.instanceId", "AUTO");
+        //线程池配置
+        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+        prop.put("org.quartz.threadPool.threadCount", "20");
+        prop.put("org.quartz.threadPool.threadPriority", "5");
+        //JobStore配置
+        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
+        //集群配置
+//        prop.put("org.quartz.jobStore.isClustered", "true");
+//        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
+//        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
+
+        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
+        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
+        factory.setQuartzProperties(prop);
+
+        factory.setSchedulerName("RenrenScheduler");
+        //延时启动
+        factory.setStartupDelay(30);
+        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
+        //可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
+        factory.setOverwriteExistingJobs(true);
+        //设置自动启动,默认为true
+        factory.setAutoStartup(true);
+
+        return factory;
+    }
+}

+ 133 - 0
src/main/java/io/renren/modules/job/controller/ScheduleJobController.java

@@ -0,0 +1,133 @@
+package io.renren.modules.job.controller;
+
+import io.renren.modules.job.entity.ScheduleJobEntity;
+import io.renren.modules.job.service.ScheduleJobService;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import io.renren.common.annotation.SysLog;
+import io.renren.common.validator.ValidatorUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 定时任务
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月28日 下午2:16:40
+ */
+@RestController
+@RequestMapping("/sys/schedule")
+public class ScheduleJobController {
+	@Autowired
+	private ScheduleJobService scheduleJobService;
+	
+	/**
+	 * 定时任务列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:schedule:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<ScheduleJobEntity> jobList = scheduleJobService.queryList(query);
+		int total = scheduleJobService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(jobList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	/**
+	 * 定时任务信息
+	 */
+	@RequestMapping("/info/{jobId}")
+	@RequiresPermissions("sys:schedule:info")
+	public R info(@PathVariable("jobId") Long jobId){
+		ScheduleJobEntity schedule = scheduleJobService.queryObject(jobId);
+		
+		return R.ok().put("schedule", schedule);
+	}
+	
+	/**
+	 * 保存定时任务
+	 */
+	@SysLog("保存定时任务")
+	@RequestMapping("/save")
+	@RequiresPermissions("sys:schedule:save")
+	public R save(@RequestBody ScheduleJobEntity scheduleJob){
+		ValidatorUtils.validateEntity(scheduleJob);
+		
+		scheduleJobService.save(scheduleJob);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 修改定时任务
+	 */
+	@SysLog("修改定时任务")
+	@RequestMapping("/update")
+	@RequiresPermissions("sys:schedule:update")
+	public R update(@RequestBody ScheduleJobEntity scheduleJob){
+		ValidatorUtils.validateEntity(scheduleJob);
+				
+		scheduleJobService.update(scheduleJob);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 删除定时任务
+	 */
+	@SysLog("删除定时任务")
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:schedule:delete")
+	public R delete(@RequestBody Long[] jobIds){
+		scheduleJobService.deleteBatch(jobIds);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 立即执行任务
+	 */
+	@SysLog("立即执行任务")
+	@RequestMapping("/run")
+	@RequiresPermissions("sys:schedule:run")
+	public R run(@RequestBody Long[] jobIds){
+		scheduleJobService.run(jobIds);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 暂停定时任务
+	 */
+	@SysLog("暂停定时任务")
+	@RequestMapping("/pause")
+	@RequiresPermissions("sys:schedule:pause")
+	public R pause(@RequestBody Long[] jobIds){
+		scheduleJobService.pause(jobIds);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 恢复定时任务
+	 */
+	@SysLog("恢复定时任务")
+	@RequestMapping("/resume")
+	@RequiresPermissions("sys:schedule:resume")
+	public R resume(@RequestBody Long[] jobIds){
+		scheduleJobService.resume(jobIds);
+		
+		return R.ok();
+	}
+
+}

+ 56 - 0
src/main/java/io/renren/modules/job/controller/ScheduleJobLogController.java

@@ -0,0 +1,56 @@
+package io.renren.modules.job.controller;
+
+import io.renren.modules.job.entity.ScheduleJobLogEntity;
+import io.renren.modules.job.service.ScheduleJobLogService;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 定时任务日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月1日 下午10:39:52
+ */
+@RestController
+@RequestMapping("/sys/scheduleLog")
+public class ScheduleJobLogController {
+	@Autowired
+	private ScheduleJobLogService scheduleJobLogService;
+	
+	/**
+	 * 定时任务日志列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:schedule:log")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<ScheduleJobLogEntity> jobList = scheduleJobLogService.queryList(query);
+		int total = scheduleJobLogService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(jobList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	/**
+	 * 定时任务日志信息
+	 */
+	@RequestMapping("/info/{logId}")
+	public R info(@PathVariable("logId") Long logId){
+		ScheduleJobLogEntity log = scheduleJobLogService.queryObject(logId);
+		
+		return R.ok().put("log", log);
+	}
+}

+ 23 - 0
src/main/java/io/renren/modules/job/dao/ScheduleJobDao.java

@@ -0,0 +1,23 @@
+package io.renren.modules.job.dao;
+
+import io.renren.modules.job.entity.ScheduleJobEntity;
+import io.renren.modules.sys.dao.BaseDao;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Map;
+
+/**
+ * 定时任务
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月1日 下午10:29:57
+ */
+@Mapper
+public interface ScheduleJobDao extends BaseDao<ScheduleJobEntity> {
+	
+	/**
+	 * 批量更新状态
+	 */
+	int updateBatch(Map<String, Object> map);
+}

+ 17 - 0
src/main/java/io/renren/modules/job/dao/ScheduleJobLogDao.java

@@ -0,0 +1,17 @@
+package io.renren.modules.job.dao;
+
+import io.renren.modules.job.entity.ScheduleJobLogEntity;
+import io.renren.modules.sys.dao.BaseDao;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 定时任务日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月1日 下午10:30:02
+ */
+@Mapper
+public interface ScheduleJobLogDao extends BaseDao<ScheduleJobLogEntity> {
+	
+}

+ 161 - 0
src/main/java/io/renren/modules/job/entity/ScheduleJobEntity.java

@@ -0,0 +1,161 @@
+package io.renren.modules.job.entity;
+
+import org.hibernate.validator.constraints.NotBlank;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 定时器
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月28日 下午12:54:44
+ */
+public class ScheduleJobEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 任务调度参数key
+	 */
+    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
+	
+	/**
+	 * 任务id
+	 */
+	private Long jobId;
+
+	/**
+	 * spring bean名称
+	 */
+	@NotBlank(message="bean名称不能为空")
+	private String beanName;
+	
+	/**
+	 * 方法名
+	 */
+	@NotBlank(message="方法名称不能为空")
+	private String methodName;
+	
+	/**
+	 * 参数
+	 */
+	private String params;
+	
+	/**
+	 * cron表达式
+	 */
+	@NotBlank(message="cron表达式不能为空")
+	private String cronExpression;
+
+	/**
+	 * 任务状态
+	 */
+	private Integer status;
+
+	/**
+	 * 备注
+	 */
+	private String remark;
+
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+
+	/**
+	 * 设置:任务id
+	 * @param jobId 任务id
+	 */
+	public void setJobId(Long jobId) {
+		this.jobId = jobId;
+	}
+
+	/**
+	 * 获取:任务id
+	 * @return Long
+	 */
+	public Long getJobId() {
+		return jobId;
+	}
+	
+	public String getBeanName() {
+		return beanName;
+	}
+
+	public void setBeanName(String beanName) {
+		this.beanName = beanName;
+	}
+
+	public String getMethodName() {
+		return methodName;
+	}
+
+	public void setMethodName(String methodName) {
+		this.methodName = methodName;
+	}
+
+	public String getParams() {
+		return params;
+	}
+
+	public void setParams(String params) {
+		this.params = params;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	/**
+	 * 设置:任务状态
+	 * @param status 任务状态
+	 */
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	/**
+	 * 获取:任务状态
+	 * @return String
+	 */
+	public Integer getStatus() {
+		return status;
+	}
+	
+	/**
+	 * 设置:cron表达式
+	 * @param cronExpression cron表达式
+	 */
+	public void setCronExpression(String cronExpression) {
+		this.cronExpression = cronExpression;
+	}
+
+	/**
+	 * 获取:cron表达式
+	 * @return String
+	 */
+	public String getCronExpression() {
+		return cronExpression;
+	}
+	
+	/**
+	 * 设置:创建时间
+	 * @param createTime 创建时间
+	 */
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	/**
+	 * 获取:创建时间
+	 * @return Date
+	 */
+	public Date getCreateTime() {
+		return createTime;
+	}
+}

+ 133 - 0
src/main/java/io/renren/modules/job/entity/ScheduleJobLogEntity.java

@@ -0,0 +1,133 @@
+package io.renren.modules.job.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 定时执行日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月1日 下午10:26:18
+ */
+public class ScheduleJobLogEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 日志id
+	 */
+	private Long logId;
+	
+	/**
+	 * 任务id
+	 */
+	private Long jobId;
+	
+	/**
+	 * spring bean名称
+	 */
+	private String beanName;
+	
+	/**
+	 * 方法名
+	 */
+	private String methodName;
+	
+	/**
+	 * 参数
+	 */
+	private String params;
+	
+	/**
+	 * 任务状态    0:成功    1:失败
+	 */
+	private Integer status;
+	
+	/**
+	 * 失败信息
+	 */
+	private String error;
+	
+	/**
+	 * 耗时(单位:毫秒)
+	 */
+	private Integer times;
+	
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+
+	public Long getLogId() {
+		return logId;
+	}
+
+	public void setLogId(Long logId) {
+		this.logId = logId;
+	}
+
+	public Long getJobId() {
+		return jobId;
+	}
+
+	public void setJobId(Long jobId) {
+		this.jobId = jobId;
+	}
+
+	public String getBeanName() {
+		return beanName;
+	}
+
+	public void setBeanName(String beanName) {
+		this.beanName = beanName;
+	}
+
+	public String getMethodName() {
+		return methodName;
+	}
+
+	public void setMethodName(String methodName) {
+		this.methodName = methodName;
+	}
+
+	public String getParams() {
+		return params;
+	}
+
+	public void setParams(String params) {
+		this.params = params;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	public String getError() {
+		return error;
+	}
+
+	public void setError(String error) {
+		this.error = error;
+	}
+
+	public Integer getTimes() {
+		return times;
+	}
+
+	public void setTimes(Integer times) {
+		this.times = times;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+	
+}

+ 37 - 0
src/main/java/io/renren/modules/job/service/ScheduleJobLogService.java

@@ -0,0 +1,37 @@
+package io.renren.modules.job.service;
+
+import io.renren.modules.job.entity.ScheduleJobLogEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 定时任务日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月1日 下午10:34:48
+ */
+public interface ScheduleJobLogService {
+
+	/**
+	 * 根据ID,查询定时任务日志
+	 */
+	ScheduleJobLogEntity queryObject(Long jobId);
+	
+	/**
+	 * 查询定时任务日志列表
+	 */
+	List<ScheduleJobLogEntity> queryList(Map<String, Object> map);
+	
+	/**
+	 * 查询总数
+	 */
+	int queryTotal(Map<String, Object> map);
+	
+	/**
+	 * 保存定时任务日志
+	 */
+	void save(ScheduleJobLogEntity log);
+	
+}

+ 66 - 0
src/main/java/io/renren/modules/job/service/ScheduleJobService.java

@@ -0,0 +1,66 @@
+package io.renren.modules.job.service;
+
+import io.renren.modules.job.entity.ScheduleJobEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 定时任务
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月28日 上午9:55:32
+ */
+public interface ScheduleJobService {
+
+	/**
+	 * 根据ID,查询定时任务
+	 */
+	ScheduleJobEntity queryObject(Long jobId);
+	
+	/**
+	 * 查询定时任务列表
+	 */
+	List<ScheduleJobEntity> queryList(Map<String, Object> map);
+	
+	/**
+	 * 查询总数
+	 */
+	int queryTotal(Map<String, Object> map);
+	
+	/**
+	 * 保存定时任务
+	 */
+	void save(ScheduleJobEntity scheduleJob);
+	
+	/**
+	 * 更新定时任务
+	 */
+	void update(ScheduleJobEntity scheduleJob);
+	
+	/**
+	 * 批量删除定时任务
+	 */
+	void deleteBatch(Long[] jobIds);
+	
+	/**
+	 * 批量更新定时任务状态
+	 */
+	int updateBatch(Long[] jobIds, int status);
+	
+	/**
+	 * 立即执行
+	 */
+	void run(Long[] jobIds);
+	
+	/**
+	 * 暂停运行
+	 */
+	void pause(Long[] jobIds);
+	
+	/**
+	 * 恢复运行
+	 */
+	void resume(Long[] jobIds);
+}

+ 38 - 0
src/main/java/io/renren/modules/job/service/impl/ScheduleJobLogServiceImpl.java

@@ -0,0 +1,38 @@
+package io.renren.modules.job.service.impl;
+
+import io.renren.modules.job.dao.ScheduleJobLogDao;
+import io.renren.modules.job.entity.ScheduleJobLogEntity;
+import io.renren.modules.job.service.ScheduleJobLogService;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service("scheduleJobLogService")
+public class ScheduleJobLogServiceImpl implements ScheduleJobLogService {
+	@Autowired
+	private ScheduleJobLogDao scheduleJobLogDao;
+	
+	@Override
+	public ScheduleJobLogEntity queryObject(Long jobId) {
+		return scheduleJobLogDao.queryObject(jobId);
+	}
+
+	@Override
+	public List<ScheduleJobLogEntity> queryList(Map<String, Object> map) {
+		return scheduleJobLogDao.queryList(map);
+	}
+
+	@Override
+	public int queryTotal(Map<String, Object> map) {
+		return scheduleJobLogDao.queryTotal(map);
+	}
+
+	@Override
+	public void save(ScheduleJobLogEntity log) {
+		scheduleJobLogDao.save(log);
+	}
+
+}

+ 126 - 0
src/main/java/io/renren/modules/job/service/impl/ScheduleJobServiceImpl.java

@@ -0,0 +1,126 @@
+package io.renren.modules.job.service.impl;
+
+import io.renren.modules.job.dao.ScheduleJobDao;
+import io.renren.modules.job.entity.ScheduleJobEntity;
+import io.renren.modules.job.service.ScheduleJobService;
+import io.renren.common.utils.Constant.ScheduleStatus;
+import io.renren.modules.job.utils.ScheduleUtils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.quartz.CronTrigger;
+import org.quartz.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service("scheduleJobService")
+public class ScheduleJobServiceImpl implements ScheduleJobService {
+	@Autowired
+    private Scheduler scheduler;
+	@Autowired
+	private ScheduleJobDao schedulerJobDao;
+	
+	/**
+	 * 项目启动时,初始化定时器
+	 */
+	@PostConstruct
+	public void init(){
+		List<ScheduleJobEntity> scheduleJobList = schedulerJobDao.queryList(new HashMap<>());
+		for(ScheduleJobEntity scheduleJob : scheduleJobList){
+			CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId());
+            //如果不存在,则创建
+            if(cronTrigger == null) {
+                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
+            }else {
+                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
+            }
+		}
+	}
+	
+	@Override
+	public ScheduleJobEntity queryObject(Long jobId) {
+		return schedulerJobDao.queryObject(jobId);
+	}
+
+	@Override
+	public List<ScheduleJobEntity> queryList(Map<String, Object> map) {
+		return schedulerJobDao.queryList(map);
+	}
+
+	@Override
+	public int queryTotal(Map<String, Object> map) {
+		return schedulerJobDao.queryTotal(map);
+	}
+
+	@Override
+	@Transactional
+	public void save(ScheduleJobEntity scheduleJob) {
+		scheduleJob.setCreateTime(new Date());
+		scheduleJob.setStatus(ScheduleStatus.NORMAL.getValue());
+        schedulerJobDao.save(scheduleJob);
+        
+        ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
+    }
+	
+	@Override
+	@Transactional
+	public void update(ScheduleJobEntity scheduleJob) {
+        ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
+                
+        schedulerJobDao.update(scheduleJob);
+    }
+
+	@Override
+	@Transactional
+    public void deleteBatch(Long[] jobIds) {
+    	for(Long jobId : jobIds){
+    		ScheduleUtils.deleteScheduleJob(scheduler, jobId);
+    	}
+    	
+    	//删除数据
+    	schedulerJobDao.deleteBatch(jobIds);
+	}
+
+	@Override
+    public int updateBatch(Long[] jobIds, int status){
+    	Map<String, Object> map = new HashMap<>();
+    	map.put("list", jobIds);
+    	map.put("status", status);
+    	return schedulerJobDao.updateBatch(map);
+    }
+    
+	@Override
+	@Transactional
+    public void run(Long[] jobIds) {
+    	for(Long jobId : jobIds){
+    		ScheduleUtils.run(scheduler, queryObject(jobId));
+    	}
+    }
+
+	@Override
+	@Transactional
+    public void pause(Long[] jobIds) {
+        for(Long jobId : jobIds){
+    		ScheduleUtils.pauseJob(scheduler, jobId);
+    	}
+        
+    	updateBatch(jobIds, ScheduleStatus.PAUSE.getValue());
+    }
+
+	@Override
+	@Transactional
+    public void resume(Long[] jobIds) {
+    	for(Long jobId : jobIds){
+    		ScheduleUtils.resumeJob(scheduler, jobId);
+    	}
+
+    	updateBatch(jobIds, ScheduleStatus.NORMAL.getValue());
+    }
+    
+}

+ 46 - 0
src/main/java/io/renren/modules/job/task/TestTask.java

@@ -0,0 +1,46 @@
+package io.renren.modules.job.task;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.service.SysUserService;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 测试定时任务(演示Demo,可删除)
+ * 
+ * testTask为spring bean的名称
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月30日 下午1:34:24
+ */
+@Component("testTask")
+public class TestTask {
+	private Logger logger = LoggerFactory.getLogger(getClass());
+	
+	@Autowired
+	private SysUserService sysUserService;
+	
+	public void test(String params){
+		logger.info("我是带参数的test方法,正在被执行,参数为:" + params);
+		
+		try {
+			Thread.sleep(1000L);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+		
+		SysUserEntity user = sysUserService.queryObject(1L);
+		System.out.println(ToStringBuilder.reflectionToString(user));
+		
+	}
+	
+	
+	public void test2(){
+		logger.info("我是不带参数的test2方法,正在被执行");
+	}
+}

+ 81 - 0
src/main/java/io/renren/modules/job/utils/ScheduleJob.java

@@ -0,0 +1,81 @@
+package io.renren.modules.job.utils;
+
+import com.google.gson.Gson;
+import io.renren.modules.job.entity.ScheduleJobEntity;
+import io.renren.modules.job.entity.ScheduleJobLogEntity;
+import io.renren.modules.job.service.ScheduleJobLogService;
+import io.renren.common.utils.SpringContextUtils;
+import org.apache.commons.lang.StringUtils;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import java.util.Date;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+
+/**
+ * 定时任务
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月30日 下午12:44:21
+ */
+public class ScheduleJob extends QuartzJobBean {
+	private Logger logger = LoggerFactory.getLogger(getClass());
+	private ExecutorService service = Executors.newSingleThreadExecutor(); 
+	
+    @Override
+    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
+		String jsonJob = context.getMergedJobDataMap().getString(ScheduleJobEntity.JOB_PARAM_KEY);
+		ScheduleJobEntity scheduleJob = new Gson().fromJson(jsonJob, ScheduleJobEntity.class);
+
+		//获取spring bean
+        ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService) SpringContextUtils.getBean("scheduleJobLogService");
+        
+        //数据库保存执行记录
+        ScheduleJobLogEntity log = new ScheduleJobLogEntity();
+        log.setJobId(scheduleJob.getJobId());
+        log.setBeanName(scheduleJob.getBeanName());
+        log.setMethodName(scheduleJob.getMethodName());
+        log.setParams(scheduleJob.getParams());
+        log.setCreateTime(new Date());
+        
+        //任务开始时间
+        long startTime = System.currentTimeMillis();
+        
+        try {
+            //执行任务
+        	logger.info("任务准备执行,任务ID:" + scheduleJob.getJobId());
+            ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(), 
+            		scheduleJob.getMethodName(), scheduleJob.getParams());
+            Future<?> future = service.submit(task);
+            
+			future.get();
+			
+			//任务执行总时长
+			long times = System.currentTimeMillis() - startTime;
+			log.setTimes((int)times);
+			//任务状态    0:成功    1:失败
+			log.setStatus(0);
+			
+			logger.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + "  总共耗时:" + times + "毫秒");
+		} catch (Exception e) {
+			logger.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e);
+			
+			//任务执行总时长
+			long times = System.currentTimeMillis() - startTime;
+			log.setTimes((int)times);
+			
+			//任务状态    0:成功    1:失败
+			log.setStatus(1);
+			log.setError(StringUtils.substring(e.toString(), 0, 2000));
+		}finally {
+			scheduleJobLogService.save(log);
+		}
+    }
+}

+ 47 - 0
src/main/java/io/renren/modules/job/utils/ScheduleRunnable.java

@@ -0,0 +1,47 @@
+package io.renren.modules.job.utils;
+
+import io.renren.common.exception.RRException;
+import io.renren.common.utils.SpringContextUtils;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Method;
+
+/**
+ * 执行定时任务
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月30日 下午12:49:33
+ */
+public class ScheduleRunnable implements Runnable {
+	private Object target;
+	private Method method;
+	private String params;
+	
+	public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException {
+		this.target = SpringContextUtils.getBean(beanName);
+		this.params = params;
+		
+		if(StringUtils.isNotBlank(params)){
+			this.method = target.getClass().getDeclaredMethod(methodName, String.class);
+		}else{
+			this.method = target.getClass().getDeclaredMethod(methodName);
+		}
+	}
+
+	@Override
+	public void run() {
+		try {
+			ReflectionUtils.makeAccessible(method);
+			if(StringUtils.isNotBlank(params)){
+				method.invoke(target, params);
+			}else{
+				method.invoke(target);
+			}
+		}catch (Exception e) {
+			throw new RRException("执行定时任务失败", e);
+		}
+	}
+
+}

+ 151 - 0
src/main/java/io/renren/modules/job/utils/ScheduleUtils.java

@@ -0,0 +1,151 @@
+package io.renren.modules.job.utils;
+
+import com.google.gson.Gson;
+import io.renren.modules.job.entity.ScheduleJobEntity;
+import io.renren.common.utils.Constant.ScheduleStatus;
+import io.renren.common.exception.RRException;
+import org.quartz.*;
+
+/**
+ * 定时任务工具类
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月30日 下午12:44:59
+ */
+public class ScheduleUtils {
+    private final static String JOB_NAME = "TASK_";
+    
+    /**
+     * 获取触发器key
+     */
+    public static TriggerKey getTriggerKey(Long jobId) {
+        return TriggerKey.triggerKey(JOB_NAME + jobId);
+    }
+    
+    /**
+     * 获取jobKey
+     */
+    public static JobKey getJobKey(Long jobId) {
+        return JobKey.jobKey(JOB_NAME + jobId);
+    }
+
+    /**
+     * 获取表达式触发器
+     */
+    public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
+        try {
+            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
+        } catch (SchedulerException e) {
+            throw new RRException("获取定时任务CronTrigger出现异常", e);
+        }
+    }
+
+    /**
+     * 创建定时任务
+     */
+    public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+        try {
+        	//构建job信息
+            JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId())).build();
+
+            //表达式调度构建器
+            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
+            		.withMisfireHandlingInstructionDoNothing();
+
+            //按新的cronExpression表达式构建一个新的trigger
+            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build();
+
+            //放入参数,运行时的方法可以获取
+            jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, new Gson().toJson(scheduleJob));
+            
+            scheduler.scheduleJob(jobDetail, trigger);
+            
+            //暂停任务
+            if(scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()){
+            	pauseJob(scheduler, scheduleJob.getJobId());
+            }
+        } catch (SchedulerException e) {
+            throw new RRException("创建定时任务失败", e);
+        }
+    }
+    
+    /**
+     * 更新定时任务
+     */
+    public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+        try {
+            TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());
+
+            //表达式调度构建器
+            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
+            		.withMisfireHandlingInstructionDoNothing();
+
+            CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());
+            
+            //按新的cronExpression表达式重新构建trigger
+            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
+            
+            //参数
+            trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, new Gson().toJson(scheduleJob));
+            
+            scheduler.rescheduleJob(triggerKey, trigger);
+            
+            //暂停任务
+            if(scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()){
+            	pauseJob(scheduler, scheduleJob.getJobId());
+            }
+            
+        } catch (SchedulerException e) {
+            throw new RRException("更新定时任务失败", e);
+        }
+    }
+
+    /**
+     * 立即执行任务
+     */
+    public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+        try {
+        	//参数
+        	JobDataMap dataMap = new JobDataMap();
+        	dataMap.put(ScheduleJobEntity.JOB_PARAM_KEY, new Gson().toJson(scheduleJob));
+        	
+            scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap);
+        } catch (SchedulerException e) {
+            throw new RRException("立即执行定时任务失败", e);
+        }
+    }
+
+    /**
+     * 暂停任务
+     */
+    public static void pauseJob(Scheduler scheduler, Long jobId) {
+        try {
+            scheduler.pauseJob(getJobKey(jobId));
+        } catch (SchedulerException e) {
+            throw new RRException("暂停定时任务失败", e);
+        }
+    }
+
+    /**
+     * 恢复任务
+     */
+    public static void resumeJob(Scheduler scheduler, Long jobId) {
+        try {
+            scheduler.resumeJob(getJobKey(jobId));
+        } catch (SchedulerException e) {
+            throw new RRException("暂停定时任务失败", e);
+        }
+    }
+
+    /**
+     * 删除定时任务
+     */
+    public static void deleteScheduleJob(Scheduler scheduler, Long jobId) {
+        try {
+            scheduler.deleteJob(getJobKey(jobId));
+        } catch (SchedulerException e) {
+            throw new RRException("删除定时任务失败", e);
+        }
+    }
+}

+ 55 - 0
src/main/java/io/renren/modules/oss/cloud/AliyunCloudStorageService.java

@@ -0,0 +1,55 @@
+package io.renren.modules.oss.cloud;
+
+import com.aliyun.oss.OSSClient;
+import io.renren.common.exception.RRException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * 阿里云存储
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-26 16:22
+ */
+public class AliyunCloudStorageService extends CloudStorageService{
+    private OSSClient client;
+
+    public AliyunCloudStorageService(CloudStorageConfig config){
+        this.config = config;
+
+        //初始化
+        init();
+    }
+
+    private void init(){
+        client = new OSSClient(config.getAliyunEndPoint(), config.getAliyunAccessKeyId(),
+                config.getAliyunAccessKeySecret());
+    }
+
+    @Override
+    public String upload(byte[] data, String path) {
+        return upload(new ByteArrayInputStream(data), path);
+    }
+
+    @Override
+    public String upload(InputStream inputStream, String path) {
+        try {
+            client.putObject(config.getAliyunBucketName(), path, inputStream);
+        } catch (Exception e){
+            throw new RRException("上传文件失败,请检查配置信息", e);
+        }
+
+        return config.getAliyunDomain() + "/" + path;
+    }
+
+    @Override
+    public String upload(byte[] data) {
+        return upload(data, getPath(config.getAliyunPrefix()));
+    }
+
+    @Override
+    public String upload(InputStream inputStream) {
+        return upload(inputStream, getPath(config.getAliyunPrefix()));
+    }
+}

+ 234 - 0
src/main/java/io/renren/modules/oss/cloud/CloudStorageConfig.java

@@ -0,0 +1,234 @@
+package io.renren.modules.oss.cloud;
+
+import io.renren.common.validator.group.AliyunGroup;
+import io.renren.common.validator.group.QcloudGroup;
+import io.renren.common.validator.group.QiniuGroup;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.Range;
+import org.hibernate.validator.constraints.URL;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 云存储配置信息
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 16:12
+ */
+public class CloudStorageConfig implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    //类型 1:七牛  2:阿里云  3:腾讯云
+    @Range(min=1, max=3, message = "类型错误")
+    private Integer type;
+
+    //七牛绑定的域名
+    @NotBlank(message="七牛绑定的域名不能为空", groups = QiniuGroup.class)
+    @URL(message = "七牛绑定的域名格式不正确", groups = QiniuGroup.class)
+    private String qiniuDomain;
+    //七牛路径前缀
+    private String qiniuPrefix;
+    //七牛ACCESS_KEY
+    @NotBlank(message="七牛AccessKey不能为空", groups = QiniuGroup.class)
+    private String qiniuAccessKey;
+    //七牛SECRET_KEY
+    @NotBlank(message="七牛SecretKey不能为空", groups = QiniuGroup.class)
+    private String qiniuSecretKey;
+    //七牛存储空间名
+    @NotBlank(message="七牛空间名不能为空", groups = QiniuGroup.class)
+    private String qiniuBucketName;
+
+    //阿里云绑定的域名
+    @NotBlank(message="阿里云绑定的域名不能为空", groups = AliyunGroup.class)
+    @URL(message = "阿里云绑定的域名格式不正确", groups = AliyunGroup.class)
+    private String aliyunDomain;
+    //阿里云路径前缀
+    private String aliyunPrefix;
+    //阿里云EndPoint
+    @NotBlank(message="阿里云EndPoint不能为空", groups = AliyunGroup.class)
+    private String aliyunEndPoint;
+    //阿里云AccessKeyId
+    @NotBlank(message="阿里云AccessKeyId不能为空", groups = AliyunGroup.class)
+    private String aliyunAccessKeyId;
+    //阿里云AccessKeySecret
+    @NotBlank(message="阿里云AccessKeySecret不能为空", groups = AliyunGroup.class)
+    private String aliyunAccessKeySecret;
+    //阿里云BucketName
+    @NotBlank(message="阿里云BucketName不能为空", groups = AliyunGroup.class)
+    private String aliyunBucketName;
+
+    //腾讯云绑定的域名
+    @NotBlank(message="腾讯云绑定的域名不能为空", groups = QcloudGroup.class)
+    @URL(message = "腾讯云绑定的域名格式不正确", groups = QcloudGroup.class)
+    private String qcloudDomain;
+    //腾讯云路径前缀
+    private String qcloudPrefix;
+    //腾讯云AppId
+    @NotNull(message="腾讯云AppId不能为空", groups = QcloudGroup.class)
+    private Integer qcloudAppId;
+    //腾讯云SecretId
+    @NotBlank(message="腾讯云SecretId不能为空", groups = QcloudGroup.class)
+    private String qcloudSecretId;
+    //腾讯云SecretKey
+    @NotBlank(message="腾讯云SecretKey不能为空", groups = QcloudGroup.class)
+    private String qcloudSecretKey;
+    //腾讯云BucketName
+    @NotBlank(message="腾讯云BucketName不能为空", groups = QcloudGroup.class)
+    private String qcloudBucketName;
+    //腾讯云COS所属地区
+    @NotBlank(message="所属地区不能为空", groups = QcloudGroup.class)
+    private String qcloudRegion;
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public String getQiniuDomain() {
+        return qiniuDomain;
+    }
+
+    public void setQiniuDomain(String qiniuDomain) {
+        this.qiniuDomain = qiniuDomain;
+    }
+
+    public String getQiniuAccessKey() {
+        return qiniuAccessKey;
+    }
+
+    public void setQiniuAccessKey(String qiniuAccessKey) {
+        this.qiniuAccessKey = qiniuAccessKey;
+    }
+
+    public String getQiniuSecretKey() {
+        return qiniuSecretKey;
+    }
+
+    public void setQiniuSecretKey(String qiniuSecretKey) {
+        this.qiniuSecretKey = qiniuSecretKey;
+    }
+
+    public String getQiniuBucketName() {
+        return qiniuBucketName;
+    }
+
+    public void setQiniuBucketName(String qiniuBucketName) {
+        this.qiniuBucketName = qiniuBucketName;
+    }
+
+    public String getQiniuPrefix() {
+        return qiniuPrefix;
+    }
+
+    public void setQiniuPrefix(String qiniuPrefix) {
+        this.qiniuPrefix = qiniuPrefix;
+    }
+
+    public String getAliyunDomain() {
+        return aliyunDomain;
+    }
+
+    public void setAliyunDomain(String aliyunDomain) {
+        this.aliyunDomain = aliyunDomain;
+    }
+
+    public String getAliyunPrefix() {
+        return aliyunPrefix;
+    }
+
+    public void setAliyunPrefix(String aliyunPrefix) {
+        this.aliyunPrefix = aliyunPrefix;
+    }
+
+    public String getAliyunEndPoint() {
+        return aliyunEndPoint;
+    }
+
+    public void setAliyunEndPoint(String aliyunEndPoint) {
+        this.aliyunEndPoint = aliyunEndPoint;
+    }
+
+    public String getAliyunAccessKeyId() {
+        return aliyunAccessKeyId;
+    }
+
+    public void setAliyunAccessKeyId(String aliyunAccessKeyId) {
+        this.aliyunAccessKeyId = aliyunAccessKeyId;
+    }
+
+    public String getAliyunAccessKeySecret() {
+        return aliyunAccessKeySecret;
+    }
+
+    public void setAliyunAccessKeySecret(String aliyunAccessKeySecret) {
+        this.aliyunAccessKeySecret = aliyunAccessKeySecret;
+    }
+
+    public String getAliyunBucketName() {
+        return aliyunBucketName;
+    }
+
+    public void setAliyunBucketName(String aliyunBucketName) {
+        this.aliyunBucketName = aliyunBucketName;
+    }
+
+    public String getQcloudDomain() {
+        return qcloudDomain;
+    }
+
+    public void setQcloudDomain(String qcloudDomain) {
+        this.qcloudDomain = qcloudDomain;
+    }
+
+    public String getQcloudPrefix() {
+        return qcloudPrefix;
+    }
+
+    public void setQcloudPrefix(String qcloudPrefix) {
+        this.qcloudPrefix = qcloudPrefix;
+    }
+
+    public Integer getQcloudAppId() {
+        return qcloudAppId;
+    }
+
+    public void setQcloudAppId(Integer qcloudAppId) {
+        this.qcloudAppId = qcloudAppId;
+    }
+
+    public String getQcloudSecretId() {
+        return qcloudSecretId;
+    }
+
+    public void setQcloudSecretId(String qcloudSecretId) {
+        this.qcloudSecretId = qcloudSecretId;
+    }
+
+    public String getQcloudSecretKey() {
+        return qcloudSecretKey;
+    }
+
+    public void setQcloudSecretKey(String qcloudSecretKey) {
+        this.qcloudSecretKey = qcloudSecretKey;
+    }
+
+    public String getQcloudBucketName() {
+        return qcloudBucketName;
+    }
+
+    public void setQcloudBucketName(String qcloudBucketName) {
+        this.qcloudBucketName = qcloudBucketName;
+    }
+
+	public String getQcloudRegion() {
+		return qcloudRegion;
+	}
+
+	public void setQcloudRegion(String qcloudRegion) {
+		this.qcloudRegion = qcloudRegion;
+	}
+}

+ 68 - 0
src/main/java/io/renren/modules/oss/cloud/CloudStorageService.java

@@ -0,0 +1,68 @@
+package io.renren.modules.oss.cloud;
+
+import io.renren.common.utils.DateUtils;
+import org.apache.commons.lang.StringUtils;
+
+import java.io.InputStream;
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 云存储(支持七牛、阿里云、腾讯云、又拍云)
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 14:58
+ */
+public abstract class CloudStorageService {
+    /** 云存储配置信息 */
+    CloudStorageConfig config;
+
+    /**
+     * 文件路径
+     * @param prefix 前缀
+     * @return 返回上传路径
+     */
+    public String getPath(String prefix) {
+        //生成uuid
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        //文件路径
+        String path = DateUtils.format(new Date(), "yyyyMMdd") + "/" + uuid;
+
+        if(StringUtils.isNotBlank(prefix)){
+            path = prefix + "/" + path;
+        }
+
+        return path;
+    }
+
+    /**
+     * 文件上传
+     * @param data    文件字节数组
+     * @param path    文件路径,包含文件名
+     * @return        返回http地址
+     */
+    public abstract String upload(byte[] data, String path);
+
+    /**
+     * 文件上传
+     * @param data    文件字节数组
+     * @return        返回http地址
+     */
+    public abstract String upload(byte[] data);
+
+    /**
+     * 文件上传
+     * @param inputStream   字节流
+     * @param path          文件路径,包含文件名
+     * @return              返回http地址
+     */
+    public abstract String upload(InputStream inputStream, String path);
+
+    /**
+     * 文件上传
+     * @param inputStream  字节流
+     * @return             返回http地址
+     */
+    public abstract String upload(InputStream inputStream);
+
+}

+ 36 - 0
src/main/java/io/renren/modules/oss/cloud/OSSFactory.java

@@ -0,0 +1,36 @@
+package io.renren.modules.oss.cloud;
+
+import io.renren.modules.sys.service.SysConfigService;
+import io.renren.common.utils.ConfigConstant;
+import io.renren.common.utils.Constant;
+import io.renren.common.utils.SpringContextUtils;
+
+/**
+ * 文件上传Factory
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-26 10:18
+ */
+public final class OSSFactory {
+    private static SysConfigService sysConfigService;
+
+    static {
+        OSSFactory.sysConfigService = (SysConfigService) SpringContextUtils.getBean("sysConfigService");
+    }
+
+    public static CloudStorageService build(){
+        //获取云存储配置信息
+        CloudStorageConfig config = sysConfigService.getConfigObject(ConfigConstant.CLOUD_STORAGE_CONFIG_KEY, CloudStorageConfig.class);
+
+        if(config.getType() == Constant.CloudService.QINIU.getValue()){
+            return new QiniuCloudStorageService(config);
+        }else if(config.getType() == Constant.CloudService.ALIYUN.getValue()){
+            return new AliyunCloudStorageService(config);
+        }else if(config.getType() == Constant.CloudService.QCLOUD.getValue()){
+            return new QcloudCloudStorageService(config);
+        }
+
+        return null;
+    }
+
+}

+ 81 - 0
src/main/java/io/renren/modules/oss/cloud/QcloudCloudStorageService.java

@@ -0,0 +1,81 @@
+package io.renren.modules.oss.cloud;
+
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.request.UploadFileRequest;
+import com.qcloud.cos.sign.Credentials;
+import io.renren.common.exception.RRException;
+import net.sf.json.JSONObject;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 腾讯云存储
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-26 20:51
+ */
+public class QcloudCloudStorageService extends CloudStorageService{
+    private COSClient client;
+
+    public QcloudCloudStorageService(CloudStorageConfig config){
+        this.config = config;
+
+        //初始化
+        init();
+    }
+
+    private void init(){
+    	Credentials credentials = new Credentials(config.getQcloudAppId(), config.getQcloudSecretId(),
+                config.getQcloudSecretKey());
+    	
+    	//初始化客户端配置
+        ClientConfig clientConfig = new ClientConfig();
+        //设置bucket所在的区域,华南:gz 华北:tj 华东:sh
+        clientConfig.setRegion(config.getQcloudRegion());
+        
+    	client = new COSClient(clientConfig, credentials);
+    }
+
+    @Override
+    public String upload(byte[] data, String path) {
+        //腾讯云必需要以"/"开头
+        if(!path.startsWith("/")) {
+            path = "/" + path;
+        }
+        
+        //上传到腾讯云
+        UploadFileRequest request = new UploadFileRequest(config.getQcloudBucketName(), path, data);
+        String response = client.uploadFile(request);
+
+        JSONObject jsonObject = JSONObject.fromObject(response);
+        if(jsonObject.getInt("code") != 0) {
+            throw new RRException("文件上传失败," + jsonObject.getString("message"));
+        }
+
+        return config.getQcloudDomain() + path;
+    }
+
+    @Override
+    public String upload(InputStream inputStream, String path) {
+    	try {
+            byte[] data = IOUtils.toByteArray(inputStream);
+            return this.upload(data, path);
+        } catch (IOException e) {
+            throw new RRException("上传文件失败", e);
+        }
+    }
+
+    @Override
+    public String upload(byte[] data) {
+        return upload(data, getPath(config.getQcloudPrefix()));
+    }
+
+    @Override
+    public String upload(InputStream inputStream) {
+        return upload(inputStream, getPath(config.getQcloudPrefix()));
+    }
+}

+ 70 - 0
src/main/java/io/renren/modules/oss/cloud/QiniuCloudStorageService.java

@@ -0,0 +1,70 @@
+package io.renren.modules.oss.cloud;
+
+import com.qiniu.common.Zone;
+import com.qiniu.http.Response;
+import com.qiniu.storage.Configuration;
+import com.qiniu.storage.UploadManager;
+import com.qiniu.util.Auth;
+import io.renren.common.exception.RRException;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 七牛云存储
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 15:41
+ */
+public class QiniuCloudStorageService extends CloudStorageService{
+    private UploadManager uploadManager;
+    private String token;
+
+    public QiniuCloudStorageService(CloudStorageConfig config){
+        this.config = config;
+
+        //初始化
+        init();
+    }
+
+    private void init(){
+        uploadManager = new UploadManager(new Configuration(Zone.autoZone()));
+        token = Auth.create(config.getQiniuAccessKey(), config.getQiniuSecretKey()).
+                uploadToken(config.getQiniuBucketName());
+    }
+
+    @Override
+    public String upload(byte[] data, String path) {
+        try {
+            Response res = uploadManager.put(data, path, token);
+            if (!res.isOK()) {
+                throw new RuntimeException("上传七牛出错:" + res.toString());
+            }
+        } catch (Exception e) {
+            throw new RRException("上传文件失败,请核对七牛配置信息", e);
+        }
+
+        return config.getQiniuDomain() + "/" + path;
+    }
+
+    @Override
+    public String upload(InputStream inputStream, String path) {
+        try {
+            byte[] data = IOUtils.toByteArray(inputStream);
+            return this.upload(data, path);
+        } catch (IOException e) {
+            throw new RRException("上传文件失败", e);
+        }
+    }
+
+    @Override
+    public String upload(byte[] data) {
+        return upload(data, getPath(config.getQiniuPrefix()));
+    }
+
+    @Override
+    public String upload(InputStream inputStream) {
+        return upload(inputStream, getPath(config.getQiniuPrefix()));
+    }
+}

+ 136 - 0
src/main/java/io/renren/modules/oss/controller/SysOssController.java

@@ -0,0 +1,136 @@
+package io.renren.modules.oss.controller;
+
+import com.google.gson.Gson;
+import io.renren.common.exception.RRException;
+import io.renren.modules.oss.entity.SysOssEntity;
+import io.renren.modules.sys.service.SysConfigService;
+import io.renren.modules.oss.service.SysOssService;
+import io.renren.common.utils.*;
+import io.renren.modules.oss.cloud.CloudStorageConfig;
+import io.renren.modules.oss.cloud.OSSFactory;
+import io.renren.common.validator.ValidatorUtils;
+import io.renren.common.validator.group.AliyunGroup;
+import io.renren.common.validator.group.QcloudGroup;
+import io.renren.common.validator.group.QiniuGroup;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+
+
+/**
+ * 文件上传
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 12:13:26
+ */
+@RestController
+@RequestMapping("sys/oss")
+public class SysOssController {
+	@Autowired
+	private SysOssService sysOssService;
+    @Autowired
+    private SysConfigService sysConfigService;
+
+    private final static String KEY = ConfigConstant.CLOUD_STORAGE_CONFIG_KEY;
+	
+	/**
+	 * 列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:oss:all")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysOssEntity> sysOssList = sysOssService.queryList(query);
+		int total = sysOssService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(sysOssList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+
+
+    /**
+     * 云存储配置信息
+     */
+    @RequestMapping("/config")
+    @RequiresPermissions("sys:oss:all")
+    public R config(){
+        CloudStorageConfig config = sysConfigService.getConfigObject(KEY, CloudStorageConfig.class);
+
+        return R.ok().put("config", config);
+    }
+
+
+	/**
+	 * 保存云存储配置信息
+	 */
+	@RequestMapping("/saveConfig")
+	@RequiresPermissions("sys:oss:all")
+	public R saveConfig(@RequestBody CloudStorageConfig config){
+		//校验类型
+		ValidatorUtils.validateEntity(config);
+
+		if(config.getType() == Constant.CloudService.QINIU.getValue()){
+			//校验七牛数据
+			ValidatorUtils.validateEntity(config, QiniuGroup.class);
+		}else if(config.getType() == Constant.CloudService.ALIYUN.getValue()){
+			//校验阿里云数据
+			ValidatorUtils.validateEntity(config, AliyunGroup.class);
+		}else if(config.getType() == Constant.CloudService.QCLOUD.getValue()){
+			//校验腾讯云数据
+			ValidatorUtils.validateEntity(config, QcloudGroup.class);
+		}
+		
+
+        sysConfigService.updateValueByKey(KEY, new Gson().toJson(config));
+
+		return R.ok();
+	}
+	
+
+	/**
+	 * 上传文件
+	 */
+	@RequestMapping("/upload")
+	@RequiresPermissions("sys:oss:all")
+	public R upload(@RequestParam("file") MultipartFile file) throws Exception {
+		if (file.isEmpty()) {
+			throw new RRException("上传文件不能为空");
+		}
+
+		//上传文件
+		String url = OSSFactory.build().upload(file.getBytes());
+
+		//保存文件信息
+		SysOssEntity ossEntity = new SysOssEntity();
+		ossEntity.setUrl(url);
+		ossEntity.setCreateDate(new Date());
+		sysOssService.save(ossEntity);
+
+		return R.ok().put("url", url);
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:oss:all")
+	public R delete(@RequestBody Long[] ids){
+		sysOssService.deleteBatch(ids);
+
+		return R.ok();
+	}
+
+}

+ 17 - 0
src/main/java/io/renren/modules/oss/dao/SysOssDao.java

@@ -0,0 +1,17 @@
+package io.renren.modules.oss.dao;
+
+import io.renren.modules.oss.entity.SysOssEntity;
+import io.renren.modules.sys.dao.BaseDao;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 文件上传
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 12:13:26
+ */
+@Mapper
+public interface SysOssDao extends BaseDao<SysOssEntity> {
+	
+}

+ 61 - 0
src/main/java/io/renren/modules/oss/entity/SysOssEntity.java

@@ -0,0 +1,61 @@
+package io.renren.modules.oss.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 文件上传
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 12:13:26
+ */
+public class SysOssEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	//
+	private Long id;
+	//URL地址
+	private String url;
+	//创建时间
+	private Date createDate;
+
+	/**
+	 * 设置:
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * 获取:
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * 设置:URL地址
+	 */
+	public void setUrl(String url) {
+		this.url = url;
+	}
+	/**
+	 * 获取:URL地址
+	 */
+	public String getUrl() {
+		return url;
+	}
+	/**
+	 * 设置:创建时间
+	 */
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+	/**
+	 * 获取:创建时间
+	 */
+	public Date getCreateDate() {
+		return createDate;
+	}
+}

+ 30 - 0
src/main/java/io/renren/modules/oss/service/SysOssService.java

@@ -0,0 +1,30 @@
+package io.renren.modules.oss.service;
+
+import io.renren.modules.oss.entity.SysOssEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 文件上传
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-25 12:13:26
+ */
+public interface SysOssService {
+	
+	SysOssEntity queryObject(Long id);
+	
+	List<SysOssEntity> queryList(Map<String, Object> map);
+	
+	int queryTotal(Map<String, Object> map);
+	
+	void save(SysOssEntity sysOss);
+	
+	void update(SysOssEntity sysOss);
+	
+	void delete(Long id);
+	
+	void deleteBatch(Long[] ids);
+}

+ 55 - 0
src/main/java/io/renren/modules/oss/service/impl/SysOssServiceImpl.java

@@ -0,0 +1,55 @@
+package io.renren.modules.oss.service.impl;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+import io.renren.modules.oss.dao.SysOssDao;
+import io.renren.modules.oss.entity.SysOssEntity;
+import io.renren.modules.oss.service.SysOssService;
+
+
+
+@Service("sysOssService")
+public class SysOssServiceImpl implements SysOssService {
+	@Autowired
+	private SysOssDao sysOssDao;
+	
+	@Override
+	public SysOssEntity queryObject(Long id){
+		return sysOssDao.queryObject(id);
+	}
+	
+	@Override
+	public List<SysOssEntity> queryList(Map<String, Object> map){
+		return sysOssDao.queryList(map);
+	}
+	
+	@Override
+	public int queryTotal(Map<String, Object> map){
+		return sysOssDao.queryTotal(map);
+	}
+	
+	@Override
+	public void save(SysOssEntity sysOss){
+		sysOssDao.save(sysOss);
+	}
+	
+	@Override
+	public void update(SysOssEntity sysOss){
+		sysOssDao.update(sysOss);
+	}
+	
+	@Override
+	public void delete(Long id){
+		sysOssDao.delete(id);
+	}
+	
+	@Override
+	public void deleteBatch(Long[] ids){
+		sysOssDao.deleteBatch(ids);
+	}
+	
+}

+ 25 - 0
src/main/java/io/renren/modules/sys/controller/AbstractController.java

@@ -0,0 +1,25 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+import org.apache.shiro.SecurityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Controller公共组件
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月9日 下午9:42:26
+ */
+public abstract class AbstractController {
+	protected Logger logger = LoggerFactory.getLogger(getClass());
+	
+	protected SysUserEntity getUser() {
+		return (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
+	}
+
+	protected Long getUserId() {
+		return getUser().getUserId();
+	}
+}

+ 98 - 0
src/main/java/io/renren/modules/sys/controller/SysConfigController.java

@@ -0,0 +1,98 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.common.annotation.SysLog;
+import io.renren.modules.sys.entity.SysConfigEntity;
+import io.renren.modules.sys.service.SysConfigService;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import io.renren.common.validator.ValidatorUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 系统配置信息
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月4日 下午6:55:53
+ */
+@RestController
+@RequestMapping("/sys/config")
+public class SysConfigController extends AbstractController {
+	@Autowired
+	private SysConfigService sysConfigService;
+	
+	/**
+	 * 所有配置列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:config:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysConfigEntity> configList = sysConfigService.queryList(query);
+		int total = sysConfigService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(configList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	
+	/**
+	 * 配置信息
+	 */
+	@RequestMapping("/info/{id}")
+	@RequiresPermissions("sys:config:info")
+	public R info(@PathVariable("id") Long id){
+		SysConfigEntity config = sysConfigService.queryObject(id);
+		
+		return R.ok().put("config", config);
+	}
+	
+	/**
+	 * 保存配置
+	 */
+	@SysLog("保存配置")
+	@RequestMapping("/save")
+	@RequiresPermissions("sys:config:save")
+	public R save(@RequestBody SysConfigEntity config){
+		ValidatorUtils.validateEntity(config);
+
+		sysConfigService.save(config);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 修改配置
+	 */
+	@SysLog("修改配置")
+	@RequestMapping("/update")
+	@RequiresPermissions("sys:config:update")
+	public R update(@RequestBody SysConfigEntity config){
+		ValidatorUtils.validateEntity(config);
+		
+		sysConfigService.update(config);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 删除配置
+	 */
+	@SysLog("删除配置")
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:config:delete")
+	public R delete(@RequestBody Long[] ids){
+		sysConfigService.deleteBatch(ids);
+		
+		return R.ok();
+	}
+
+}

+ 48 - 0
src/main/java/io/renren/modules/sys/controller/SysLogController.java

@@ -0,0 +1,48 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.modules.sys.entity.SysLogEntity;
+import io.renren.modules.sys.service.SysLogService;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 系统日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-08 10:40:56
+ */
+@Controller
+@RequestMapping("/sys/log")
+public class SysLogController {
+	@Autowired
+	private SysLogService sysLogService;
+	
+	/**
+	 * 列表
+	 */
+	@ResponseBody
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:log:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysLogEntity> sysLogList = sysLogService.queryList(query);
+		int total = sysLogService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(sysLogList, total, query.getLimit(), query.getPage());
+		return R.ok().put("page", pageUtil);
+	}
+	
+}

+ 56 - 0
src/main/java/io/renren/modules/sys/controller/SysLoginController.java

@@ -0,0 +1,56 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.common.utils.R;
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.service.SysUserService;
+import io.renren.modules.sys.service.SysUserTokenService;
+import org.apache.shiro.crypto.hash.Sha256Hash;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * 登录相关
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月10日 下午1:15:31
+ */
+@RestController
+public class SysLoginController {
+	@Autowired
+	private SysUserService sysUserService;
+	@Autowired
+	private SysUserTokenService sysUserTokenService;
+	
+	
+	/**
+	 * 登录
+	 */
+	@RequestMapping(value = "/sys/login", method = RequestMethod.POST)
+	public Map<String, Object> login(String username, String password)throws IOException {
+		// TODO: 2017-06-02 登录失败10次,锁5分钟
+
+		//用户信息
+		SysUserEntity user = sysUserService.queryByUserName(username);
+
+		//账号不存在、密码错误
+		if(user == null || !user.getPassword().equals(new Sha256Hash(password, user.getSalt()).toHex())) {
+			return R.error("账号或密码不正确");
+		}
+
+		//账号锁定
+		if(user.getStatus() == 0){
+			return R.error("账号已被锁定,请联系管理员");
+		}
+
+		//生成token,并保存到数据库
+		R r = sysUserTokenService.createToken(user.getUserId());
+		return r;
+	}
+	
+}

+ 203 - 0
src/main/java/io/renren/modules/sys/controller/SysMenuController.java

@@ -0,0 +1,203 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.common.annotation.SysLog;
+import io.renren.common.exception.RRException;
+import io.renren.common.utils.Constant;
+import io.renren.common.utils.Constant.MenuType;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import io.renren.modules.sys.entity.SysMenuEntity;
+import io.renren.modules.sys.service.ShiroService;
+import io.renren.modules.sys.service.SysMenuService;
+import org.apache.commons.lang.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 系统菜单
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年10月27日 下午9:58:15
+ */
+@RestController
+@RequestMapping("/sys/menu")
+public class SysMenuController extends AbstractController {
+	@Autowired
+	private SysMenuService sysMenuService;
+	@Autowired
+	private ShiroService shiroService;
+	
+	/**
+	 * 所有菜单列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:menu:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysMenuEntity> menuList = sysMenuService.queryList(query);
+		int total = sysMenuService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(menuList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	/**
+	 * 选择菜单(添加、修改菜单)
+	 */
+	@RequestMapping("/select")
+	@RequiresPermissions("sys:menu:select")
+	public R select(){
+		//查询列表数据
+		List<SysMenuEntity> menuList = sysMenuService.queryNotButtonList();
+		
+		//添加顶级菜单
+		SysMenuEntity root = new SysMenuEntity();
+		root.setMenuId(0L);
+		root.setName("一级菜单");
+		root.setParentId(-1L);
+		root.setOpen(true);
+		menuList.add(root);
+		
+		return R.ok().put("menuList", menuList);
+	}
+	
+	/**
+	 * 角色授权菜单
+	 */
+	@RequestMapping("/perms")
+	@RequiresPermissions("sys:menu:perms")
+	public R perms(){
+		//查询列表数据
+		List<SysMenuEntity> menuList = null;
+		
+		//只有超级管理员,才能查看所有管理员列表
+		if(getUserId() == Constant.SUPER_ADMIN){
+			menuList = sysMenuService.queryList(new HashMap<String, Object>());
+		}else{
+			menuList = sysMenuService.queryUserList(getUserId());
+		}
+		
+		return R.ok().put("menuList", menuList);
+	}
+	
+	/**
+	 * 菜单信息
+	 */
+	@RequestMapping("/info/{menuId}")
+	@RequiresPermissions("sys:menu:info")
+	public R info(@PathVariable("menuId") Long menuId){
+		SysMenuEntity menu = sysMenuService.queryObject(menuId);
+		return R.ok().put("menu", menu);
+	}
+	
+	/**
+	 * 保存
+	 */
+	@SysLog("保存菜单")
+	@RequestMapping("/save")
+	@RequiresPermissions("sys:menu:save")
+	public R save(@RequestBody SysMenuEntity menu){
+		//数据校验
+		verifyForm(menu);
+		
+		sysMenuService.save(menu);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 修改
+	 */
+	@SysLog("修改菜单")
+	@RequestMapping("/update")
+	@RequiresPermissions("sys:menu:update")
+	public R update(@RequestBody SysMenuEntity menu){
+		//数据校验
+		verifyForm(menu);
+				
+		sysMenuService.update(menu);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 删除
+	 */
+	@SysLog("删除菜单")
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:menu:delete")
+	public R delete(@RequestBody Long[] menuIds){
+		for(Long menuId : menuIds){
+			if(menuId.longValue() <= 30){
+				return R.error("系统菜单,不能删除");
+			}
+		}
+		sysMenuService.deleteBatch(menuIds);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 用户菜单列表
+	 */
+	@RequestMapping("/user")
+	public R user(){
+		List<SysMenuEntity> menuList = sysMenuService.getUserMenuList(getUserId());
+		Set<String> permissions = shiroService.getUserPermissions(getUserId());
+		return R.ok().put("menuList", menuList).put("permissions", permissions);
+	}
+	
+	/**
+	 * 验证参数是否正确
+	 */
+	private void verifyForm(SysMenuEntity menu){
+		if(StringUtils.isBlank(menu.getName())){
+			throw new RRException("菜单名称不能为空");
+		}
+		
+		if(menu.getParentId() == null){
+			throw new RRException("上级菜单不能为空");
+		}
+		
+		//菜单
+		if(menu.getType() == MenuType.MENU.getValue()){
+			if(StringUtils.isBlank(menu.getUrl())){
+				throw new RRException("菜单URL不能为空");
+			}
+		}
+		
+		//上级菜单类型
+		int parentType = MenuType.CATALOG.getValue();
+		if(menu.getParentId() != 0){
+			SysMenuEntity parentMenu = sysMenuService.queryObject(menu.getParentId());
+			parentType = parentMenu.getType();
+		}
+		
+		//目录、菜单
+		if(menu.getType() == MenuType.CATALOG.getValue() ||
+				menu.getType() == MenuType.MENU.getValue()){
+			if(parentType != MenuType.CATALOG.getValue()){
+				throw new RRException("上级菜单只能为目录类型");
+			}
+			return ;
+		}
+		
+		//按钮
+		if(menu.getType() == MenuType.BUTTON.getValue()){
+			if(parentType != MenuType.MENU.getValue()){
+				throw new RRException("上级菜单只能为菜单类型");
+			}
+			return ;
+		}
+	}
+}

+ 129 - 0
src/main/java/io/renren/modules/sys/controller/SysRoleController.java

@@ -0,0 +1,129 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.common.annotation.SysLog;
+import io.renren.modules.sys.entity.SysRoleEntity;
+import io.renren.modules.sys.service.SysRoleMenuService;
+import io.renren.modules.sys.service.SysRoleService;
+import io.renren.common.utils.Constant;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import io.renren.common.validator.ValidatorUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 角色管理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年11月8日 下午2:18:33
+ */
+@RestController
+@RequestMapping("/sys/role")
+public class SysRoleController extends AbstractController {
+	@Autowired
+	private SysRoleService sysRoleService;
+	@Autowired
+	private SysRoleMenuService sysRoleMenuService;
+	
+	/**
+	 * 角色列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:role:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//如果不是超级管理员,则只查询自己创建的角色列表
+		if(getUserId() != Constant.SUPER_ADMIN){
+			params.put("createUserId", getUserId());
+		}
+		
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysRoleEntity> list = sysRoleService.queryList(query);
+		int total = sysRoleService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(list, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	/**
+	 * 角色列表
+	 */
+	@RequestMapping("/select")
+	@RequiresPermissions("sys:role:select")
+	public R select(){
+		Map<String, Object> map = new HashMap<>();
+		
+		//如果不是超级管理员,则只查询自己所拥有的角色列表
+		if(getUserId() != Constant.SUPER_ADMIN){
+			map.put("createUserId", getUserId());
+		}
+		List<SysRoleEntity> list = sysRoleService.queryList(map);
+		
+		return R.ok().put("list", list);
+	}
+	
+	/**
+	 * 角色信息
+	 */
+	@RequestMapping("/info/{roleId}")
+	@RequiresPermissions("sys:role:info")
+	public R info(@PathVariable("roleId") Long roleId){
+		SysRoleEntity role = sysRoleService.queryObject(roleId);
+		
+		//查询角色对应的菜单
+		List<Long> menuIdList = sysRoleMenuService.queryMenuIdList(roleId);
+		role.setMenuIdList(menuIdList);
+		
+		return R.ok().put("role", role);
+	}
+	
+	/**
+	 * 保存角色
+	 */
+	@SysLog("保存角色")
+	@RequestMapping("/save")
+	@RequiresPermissions("sys:role:save")
+	public R save(@RequestBody SysRoleEntity role){
+		ValidatorUtils.validateEntity(role);
+		
+		role.setCreateUserId(getUserId());
+		sysRoleService.save(role);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 修改角色
+	 */
+	@SysLog("修改角色")
+	@RequestMapping("/update")
+	@RequiresPermissions("sys:role:update")
+	public R update(@RequestBody SysRoleEntity role){
+		ValidatorUtils.validateEntity(role);
+		
+		role.setCreateUserId(getUserId());
+		sysRoleService.update(role);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 删除角色
+	 */
+	@SysLog("删除角色")
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:role:delete")
+	public R delete(@RequestBody Long[] roleIds){
+		sysRoleService.deleteBatch(roleIds);
+		
+		return R.ok();
+	}
+}

+ 154 - 0
src/main/java/io/renren/modules/sys/controller/SysUserController.java

@@ -0,0 +1,154 @@
+package io.renren.modules.sys.controller;
+
+import io.renren.common.annotation.SysLog;
+import io.renren.common.utils.Constant;
+import io.renren.common.utils.PageUtils;
+import io.renren.common.utils.Query;
+import io.renren.common.utils.R;
+import io.renren.common.validator.Assert;
+import io.renren.common.validator.ValidatorUtils;
+import io.renren.common.validator.group.AddGroup;
+import io.renren.common.validator.group.UpdateGroup;
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.service.SysUserRoleService;
+import io.renren.modules.sys.service.SysUserService;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.apache.shiro.crypto.hash.Sha256Hash;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 系统用户
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年10月31日 上午10:40:10
+ */
+@RestController
+@RequestMapping("/sys/user")
+public class SysUserController extends AbstractController {
+	@Autowired
+	private SysUserService sysUserService;
+	@Autowired
+	private SysUserRoleService sysUserRoleService;
+	
+	/**
+	 * 所有用户列表
+	 */
+	@RequestMapping("/list")
+	@RequiresPermissions("sys:user:list")
+	public R list(@RequestParam Map<String, Object> params){
+		//只有超级管理员,才能查看所有管理员列表
+		if(getUserId() != Constant.SUPER_ADMIN){
+			params.put("createUserId", getUserId());
+		}
+		
+		//查询列表数据
+		Query query = new Query(params);
+		List<SysUserEntity> userList = sysUserService.queryList(query);
+		int total = sysUserService.queryTotal(query);
+		
+		PageUtils pageUtil = new PageUtils(userList, total, query.getLimit(), query.getPage());
+		
+		return R.ok().put("page", pageUtil);
+	}
+	
+	/**
+	 * 获取登录的用户信息
+	 */
+	@RequestMapping("/info")
+	public R info(){
+		return R.ok().put("user", getUser());
+	}
+	
+	/**
+	 * 修改登录用户密码
+	 */
+	@SysLog("修改密码")
+	@RequestMapping("/password")
+	public R password(String password, String newPassword){
+		Assert.isBlank(newPassword, "新密码不为能空");
+		
+		//sha256加密
+		password = new Sha256Hash(password, getUser().getSalt()).toHex();
+		//sha256加密
+		newPassword = new Sha256Hash(newPassword, getUser().getSalt()).toHex();
+				
+		//更新密码
+		int count = sysUserService.updatePassword(getUserId(), password, newPassword);
+		if(count == 0){
+			return R.error("原密码不正确");
+		}
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 用户信息
+	 */
+	@RequestMapping("/info/{userId}")
+	@RequiresPermissions("sys:user:info")
+	public R info(@PathVariable("userId") Long userId){
+		SysUserEntity user = sysUserService.queryObject(userId);
+		
+		//获取用户所属的角色列表
+		List<Long> roleIdList = sysUserRoleService.queryRoleIdList(userId);
+		user.setRoleIdList(roleIdList);
+		
+		return R.ok().put("user", user);
+	}
+	
+	/**
+	 * 保存用户
+	 */
+	@SysLog("保存用户")
+	@RequestMapping("/save")
+	@RequiresPermissions("sys:user:save")
+	public R save(@RequestBody SysUserEntity user){
+		ValidatorUtils.validateEntity(user, AddGroup.class);
+		
+		user.setCreateUserId(getUserId());
+		sysUserService.save(user);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 修改用户
+	 */
+	@SysLog("修改用户")
+	@RequestMapping("/update")
+	@RequiresPermissions("sys:user:update")
+	public R update(@RequestBody SysUserEntity user){
+		ValidatorUtils.validateEntity(user, UpdateGroup.class);
+		
+		user.setCreateUserId(getUserId());
+		sysUserService.update(user);
+		
+		return R.ok();
+	}
+	
+	/**
+	 * 删除用户
+	 */
+	@SysLog("删除用户")
+	@RequestMapping("/delete")
+	@RequiresPermissions("sys:user:delete")
+	public R delete(@RequestBody Long[] userIds){
+		if(ArrayUtils.contains(userIds, 1L)){
+			return R.error("系统管理员不能删除");
+		}
+		
+		if(ArrayUtils.contains(userIds, getUserId())){
+			return R.error("当前用户不能删除");
+		}
+		
+		sysUserService.deleteBatch(userIds);
+		
+		return R.ok();
+	}
+}

+ 42 - 0
src/main/java/io/renren/modules/sys/dao/BaseDao.java

@@ -0,0 +1,42 @@
+package io.renren.modules.sys.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 基础Dao(还需在XML文件里,有对应的SQL语句)
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:31:36
+ */
+public interface BaseDao<T> {
+	
+	void save(T t);
+	
+	void save(Map<String, Object> map);
+	
+	void saveBatch(List<T> list);
+	
+	int update(T t);
+	
+	int update(Map<String, Object> map);
+	
+	int delete(Object id);
+	
+	int delete(Map<String, Object> map);
+	
+	int deleteBatch(Object[] id);
+
+	T queryObject(Object id);
+	
+	List<T> queryList(Map<String, Object> map);
+	
+	List<T> queryList(Object id);
+	
+	int queryTotal(Map<String, Object> map);
+
+	int queryTotal();
+}

+ 27 - 0
src/main/java/io/renren/modules/sys/dao/SysConfigDao.java

@@ -0,0 +1,27 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysConfigEntity;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 系统配置信息
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月4日 下午6:46:16
+ */
+@Mapper
+public interface SysConfigDao extends BaseDao<SysConfigEntity> {
+	
+	/**
+	 * 根据key,查询value
+	 */
+	String queryByKey(String paramKey);
+	
+	/**
+	 * 根据key,更新value
+	 */
+	int updateValueByKey(@Param("key") String key, @Param("value") String value);
+	
+}

+ 16 - 0
src/main/java/io/renren/modules/sys/dao/SysLogDao.java

@@ -0,0 +1,16 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysLogEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 系统日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-08 10:40:56
+ */
+@Mapper
+public interface SysLogDao extends BaseDao<SysLogEntity> {
+	
+}

+ 33 - 0
src/main/java/io/renren/modules/sys/dao/SysMenuDao.java

@@ -0,0 +1,33 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysMenuEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 菜单管理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:33:01
+ */
+@Mapper
+public interface SysMenuDao extends BaseDao<SysMenuEntity> {
+	
+	/**
+	 * 根据父菜单,查询子菜单
+	 * @param parentId 父菜单ID
+	 */
+	List<SysMenuEntity> queryListParentId(Long parentId);
+	
+	/**
+	 * 获取不包含按钮的菜单列表
+	 */
+	List<SysMenuEntity> queryNotButtonList();
+	
+	/**
+	 * 查询用户的权限列表
+	 */
+	List<SysMenuEntity> queryUserList(Long userId);
+}

+ 22 - 0
src/main/java/io/renren/modules/sys/dao/SysRoleDao.java

@@ -0,0 +1,22 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysRoleEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 角色管理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:33:33
+ */
+@Mapper
+public interface SysRoleDao extends BaseDao<SysRoleEntity> {
+	
+	/**
+	 * 查询用户创建的角色ID列表
+	 */
+	List<Long> queryRoleIdList(Long createUserId);
+}

+ 22 - 0
src/main/java/io/renren/modules/sys/dao/SysRoleMenuDao.java

@@ -0,0 +1,22 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysRoleMenuEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 角色与菜单对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:33:46
+ */
+@Mapper
+public interface SysRoleMenuDao extends BaseDao<SysRoleMenuEntity> {
+	
+	/**
+	 * 根据角色ID,获取菜单ID列表
+	 */
+	List<Long> queryMenuIdList(Long roleId);
+}

+ 39 - 0
src/main/java/io/renren/modules/sys/dao/SysUserDao.java

@@ -0,0 +1,39 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 系统用户
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:34:11
+ */
+@Mapper
+public interface SysUserDao extends BaseDao<SysUserEntity> {
+	
+	/**
+	 * 查询用户的所有权限
+	 * @param userId  用户ID
+	 */
+	List<String> queryAllPerms(Long userId);
+	
+	/**
+	 * 查询用户的所有菜单ID
+	 */
+	List<Long> queryAllMenuId(Long userId);
+	
+	/**
+	 * 根据用户名,查询系统用户
+	 */
+	SysUserEntity queryByUserName(String username);
+	
+	/**
+	 * 修改密码
+	 */
+	int updatePassword(Map<String, Object> map);
+}

+ 22 - 0
src/main/java/io/renren/modules/sys/dao/SysUserRoleDao.java

@@ -0,0 +1,22 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysUserRoleEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 用户与角色对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:34:46
+ */
+@Mapper
+public interface SysUserRoleDao extends BaseDao<SysUserRoleEntity> {
+	
+	/**
+	 * 根据用户ID,获取角色ID列表
+	 */
+	List<Long> queryRoleIdList(Long userId);
+}

+ 20 - 0
src/main/java/io/renren/modules/sys/dao/SysUserTokenDao.java

@@ -0,0 +1,20 @@
+package io.renren.modules.sys.dao;
+
+import io.renren.modules.sys.entity.SysUserTokenEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 系统用户Token
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-23 15:22:07
+ */
+@Mapper
+public interface SysUserTokenDao extends BaseDao<SysUserTokenEntity> {
+    
+    SysUserTokenEntity queryByUserId(Long userId);
+
+    SysUserTokenEntity queryByToken(String token);
+	
+}

+ 45 - 0
src/main/java/io/renren/modules/sys/entity/SysConfigEntity.java

@@ -0,0 +1,45 @@
+package io.renren.modules.sys.entity;
+
+
+import org.hibernate.validator.constraints.NotBlank;
+
+/**
+ * 系统配置信息
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月4日 下午6:43:36
+ */
+public class SysConfigEntity {
+	private Long id;
+	@NotBlank(message="参数名不能为空")
+	private String key;
+	@NotBlank(message="参数值不能为空")
+	private String value; 
+	private String remark;
+	
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public String getKey() {
+		return key;
+	}
+	public void setKey(String key) {
+		this.key = key;
+	}
+	public String getValue() {
+		return value;
+	}
+	public void setValue(String value) {
+		this.value = value;
+	}
+	public String getRemark() {
+		return remark;
+	}
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+}

+ 115 - 0
src/main/java/io/renren/modules/sys/entity/SysLogEntity.java

@@ -0,0 +1,115 @@
+package io.renren.modules.sys.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 系统日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-08 10:40:56
+ */
+public class SysLogEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	private Long id;
+	//用户名
+	private String username;
+	//用户操作
+	private String operation;
+	//请求方法
+	private String method;
+	//请求参数
+	private String params;
+	//IP地址
+	private String ip;
+	//创建时间
+	private Date createDate;
+
+	/**
+	 * 设置:
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * 获取:
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * 设置:用户名
+	 */
+	public void setUsername(String username) {
+		this.username = username;
+	}
+	/**
+	 * 获取:用户名
+	 */
+	public String getUsername() {
+		return username;
+	}
+	/**
+	 * 设置:用户操作
+	 */
+	public void setOperation(String operation) {
+		this.operation = operation;
+	}
+	/**
+	 * 获取:用户操作
+	 */
+	public String getOperation() {
+		return operation;
+	}
+	/**
+	 * 设置:请求方法
+	 */
+	public void setMethod(String method) {
+		this.method = method;
+	}
+	/**
+	 * 获取:请求方法
+	 */
+	public String getMethod() {
+		return method;
+	}
+	/**
+	 * 设置:请求参数
+	 */
+	public void setParams(String params) {
+		this.params = params;
+	}
+	/**
+	 * 获取:请求参数
+	 */
+	public String getParams() {
+		return params;
+	}
+	/**
+	 * 设置:IP地址
+	 */
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+	/**
+	 * 获取:IP地址
+	 */
+	public String getIp() {
+		return ip;
+	}
+	/**
+	 * 设置:创建时间
+	 */
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+	/**
+	 * 获取:创建时间
+	 */
+	public Date getCreateDate() {
+		return createDate;
+	}
+}

+ 196 - 0
src/main/java/io/renren/modules/sys/entity/SysMenuEntity.java

@@ -0,0 +1,196 @@
+package io.renren.modules.sys.entity;
+
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 菜单管理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:26:39
+ */
+public class SysMenuEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	/**
+	 * 菜单ID
+	 */
+	private Long menuId;
+
+	/**
+	 * 父菜单ID,一级菜单为0
+	 */
+	private Long parentId;
+	
+	/**
+	 * 父菜单名称
+	 */
+	private String parentName;
+
+	/**
+	 * 菜单名称
+	 */
+	private String name;
+
+	/**
+	 * 菜单URL
+	 */
+	private String url;
+
+	/**
+	 * 授权(多个用逗号分隔,如:user:list,user:create)
+	 */
+	private String perms;
+
+	/**
+	 * 类型     0:目录   1:菜单   2:按钮
+	 */
+	private Integer type;
+
+	/**
+	 * 菜单图标
+	 */
+	private String icon;
+
+	/**
+	 * 排序
+	 */
+	private Integer orderNum;
+	
+	/**
+	 * ztree属性
+	 */
+	private Boolean open;
+	
+	private List<?> list;
+
+	public void setMenuId(Long menuId) {
+		this.menuId = menuId;
+	}
+
+	public Long getMenuId() {
+		return menuId;
+	}
+	
+	/**
+	 * 设置:父菜单ID,一级菜单为0
+	 * @param parentId 父菜单ID,一级菜单为0
+	 */
+	public void setParentId(Long parentId) {
+		this.parentId = parentId;
+	}
+
+	/**
+	 * 获取:父菜单ID,一级菜单为0
+	 * @return Long
+	 */
+	public Long getParentId() {
+		return parentId;
+	}
+	
+	/**
+	 * 设置:菜单名称
+	 * @param name 菜单名称
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * 获取:菜单名称
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * 设置:菜单URL
+	 * @param url 菜单URL
+	 */
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
+	/**
+	 * 获取:菜单URL
+	 * @return String
+	 */
+	public String getUrl() {
+		return url;
+	}
+	
+	public String getPerms() {
+		return perms;
+	}
+
+	public void setPerms(String perms) {
+		this.perms = perms;
+	}
+
+	public Integer getType() {
+		return type;
+	}
+
+	public void setType(Integer type) {
+		this.type = type;
+	}
+
+	/**
+	 * 设置:菜单图标
+	 * @param icon 菜单图标
+	 */
+	public void setIcon(String icon) {
+		this.icon = icon;
+	}
+
+	/**
+	 * 获取:菜单图标
+	 * @return String
+	 */
+	public String getIcon() {
+		return icon;
+	}
+	
+	/**
+	 * 设置:排序
+	 * @param orderNum 排序
+	 */
+	public void setOrderNum(Integer orderNum) {
+		this.orderNum = orderNum;
+	}
+
+	/**
+	 * 获取:排序
+	 * @return Integer
+	 */
+	public Integer getOrderNum() {
+		return orderNum;
+	}
+
+	public List<?> getList() {
+		return list;
+	}
+
+	public void setList(List<?> list) {
+		this.list = list;
+	}
+
+	public String getParentName() {
+		return parentName;
+	}
+
+	public void setParentName(String parentName) {
+		this.parentName = parentName;
+	}
+
+	public Boolean getOpen() {
+		return open;
+	}
+
+	public void setOpen(Boolean open) {
+		this.open = open;
+	}
+}

+ 120 - 0
src/main/java/io/renren/modules/sys/entity/SysRoleEntity.java

@@ -0,0 +1,120 @@
+package io.renren.modules.sys.entity;
+
+
+import org.hibernate.validator.constraints.NotBlank;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 角色
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:27:38
+ */
+public class SysRoleEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	/**
+	 * 角色ID
+	 */
+	private Long roleId;
+
+	/**
+	 * 角色名称
+	 */
+	@NotBlank(message="角色名称不能为空")
+	private String roleName;
+
+	/**
+	 * 备注
+	 */
+	private String remark;
+	
+	/**
+	 * 创建者ID
+	 */
+	private Long createUserId;
+	
+	private List<Long> menuIdList;
+	
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+
+	/**
+	 * 设置:
+	 * @param roleId 
+	 */
+	public void setRoleId(Long roleId) {
+		this.roleId = roleId;
+	}
+
+	/**
+	 * 获取:
+	 * @return Long
+	 */
+	public Long getRoleId() {
+		return roleId;
+	}
+	
+	/**
+	 * 设置:角色名称
+	 * @param roleName 角色名称
+	 */
+	public void setRoleName(String roleName) {
+		this.roleName = roleName;
+	}
+
+	/**
+	 * 获取:角色名称
+	 * @return String
+	 */
+	public String getRoleName() {
+		return roleName;
+	}
+	
+	/**
+	 * 设置:备注
+	 * @param remark 备注
+	 */
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	/**
+	 * 获取:备注
+	 * @return String
+	 */
+	public String getRemark() {
+		return remark;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public List<Long> getMenuIdList() {
+		return menuIdList;
+	}
+
+	public void setMenuIdList(List<Long> menuIdList) {
+		this.menuIdList = menuIdList;
+	}
+
+	public Long getCreateUserId() {
+		return createUserId;
+	}
+
+	public void setCreateUserId(Long createUserId) {
+		this.createUserId = createUserId;
+	}
+	
+}

+ 76 - 0
src/main/java/io/renren/modules/sys/entity/SysRoleMenuEntity.java

@@ -0,0 +1,76 @@
+package io.renren.modules.sys.entity;
+
+
+import java.io.Serializable;
+
+/**
+ * 角色与菜单对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:28:13
+ */
+public class SysRoleMenuEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	private Long id;
+
+	/**
+	 * 角色ID
+	 */
+	private Long roleId;
+
+	/**
+	 * 菜单ID
+	 */
+	private Long menuId;
+
+	/**
+	 * 设置:
+	 * @param id 
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	/**
+	 * 获取:
+	 * @return Long
+	 */
+	public Long getId() {
+		return id;
+	}
+	
+	/**
+	 * 设置:角色ID
+	 * @param roleId 角色ID
+	 */
+	public void setRoleId(Long roleId) {
+		this.roleId = roleId;
+	}
+
+	/**
+	 * 获取:角色ID
+	 * @return Long
+	 */
+	public Long getRoleId() {
+		return roleId;
+	}
+	
+	/**
+	 * 设置:菜单ID
+	 * @param menuId 菜单ID
+	 */
+	public void setMenuId(Long menuId) {
+		this.menuId = menuId;
+	}
+
+	/**
+	 * 获取:菜单ID
+	 * @return Long
+	 */
+	public Long getMenuId() {
+		return menuId;
+	}
+	
+}

+ 211 - 0
src/main/java/io/renren/modules/sys/entity/SysUserEntity.java

@@ -0,0 +1,211 @@
+package io.renren.modules.sys.entity;
+
+import io.renren.common.validator.group.AddGroup;
+import io.renren.common.validator.group.UpdateGroup;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotBlank;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 系统用户
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:28:55
+ */
+public class SysUserEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	/**
+	 * 用户ID
+	 */
+	private Long userId;
+
+	/**
+	 * 用户名
+	 */
+	@NotBlank(message="用户名不能为空", groups = {AddGroup.class, UpdateGroup.class})
+	private String username;
+
+	/**
+	 * 密码
+	 */
+	@NotBlank(message="密码不能为空", groups = AddGroup.class)
+	private String password;
+
+	/**
+	 * 盐
+	 */
+	private String salt;
+
+	/**
+	 * 邮箱
+	 */
+	@NotBlank(message="邮箱不能为空", groups = {AddGroup.class, UpdateGroup.class})
+	@Email(message="邮箱格式不正确", groups = {AddGroup.class, UpdateGroup.class})
+	private String email;
+
+	/**
+	 * 手机号
+	 */
+	private String mobile;
+
+	/**
+	 * 状态  0:禁用   1:正常
+	 */
+	private Integer status;
+	
+	/**
+	 * 角色ID列表
+	 */
+	private List<Long> roleIdList;
+	
+	/**
+	 * 创建者ID
+	 */
+	private Long createUserId;
+
+	/**
+	 * 创建时间
+	 */
+	private Date createTime;
+
+	/**
+	 * 设置:
+	 * @param userId 
+	 */
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	/**
+	 * 获取:
+	 * @return Long
+	 */
+	public Long getUserId() {
+		return userId;
+	}
+	
+	/**
+	 * 设置:用户名
+	 * @param username 用户名
+	 */
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	/**
+	 * 获取:用户名
+	 * @return String
+	 */
+	public String getUsername() {
+		return username;
+	}
+	
+	/**
+	 * 设置:密码
+	 * @param password 密码
+	 */
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	/**
+	 * 获取:密码
+	 * @return String
+	 */
+	public String getPassword() {
+		return password;
+	}
+	
+	/**
+	 * 设置:邮箱
+	 * @param email 邮箱
+	 */
+	public void setEmail(String email) {
+		this.email = email;
+	}
+
+	/**
+	 * 获取:邮箱
+	 * @return String
+	 */
+	public String getEmail() {
+		return email;
+	}
+	
+	/**
+	 * 设置:手机号
+	 * @param mobile 手机号
+	 */
+	public void setMobile(String mobile) {
+		this.mobile = mobile;
+	}
+
+	/**
+	 * 获取:手机号
+	 * @return String
+	 */
+	public String getMobile() {
+		return mobile;
+	}
+	
+	/**
+	 * 设置:状态  0:禁用   1:正常
+	 * @param status 状态  0:禁用   1:正常
+	 */
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	/**
+	 * 获取:状态  0:禁用   1:正常
+	 * @return Integer
+	 */
+	public Integer getStatus() {
+		return status;
+	}
+	
+	/**
+	 * 设置:创建时间
+	 * @param createTime 创建时间
+	 */
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	/**
+	 * 获取:创建时间
+	 * @return Date
+	 */
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public List<Long> getRoleIdList() {
+		return roleIdList;
+	}
+
+	public void setRoleIdList(List<Long> roleIdList) {
+		this.roleIdList = roleIdList;
+	}
+
+	public Long getCreateUserId() {
+		return createUserId;
+	}
+
+	public void setCreateUserId(Long createUserId) {
+		this.createUserId = createUserId;
+	}
+
+	public String getSalt() {
+		return salt;
+	}
+
+	public void setSalt(String salt) {
+		this.salt = salt;
+	}
+}

+ 76 - 0
src/main/java/io/renren/modules/sys/entity/SysUserRoleEntity.java

@@ -0,0 +1,76 @@
+package io.renren.modules.sys.entity;
+
+
+import java.io.Serializable;
+
+/**
+ * 用户与角色对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:28:39
+ */
+public class SysUserRoleEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	private Long id;
+
+	/**
+	 * 用户ID
+	 */
+	private Long userId;
+
+	/**
+	 * 角色ID
+	 */
+	private Long roleId;
+
+	/**
+	 * 设置:
+	 * @param id 
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	/**
+	 * 获取:
+	 * @return Long
+	 */
+	public Long getId() {
+		return id;
+	}
+	
+	/**
+	 * 设置:用户ID
+	 * @param userId 用户ID
+	 */
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	/**
+	 * 获取:用户ID
+	 * @return Long
+	 */
+	public Long getUserId() {
+		return userId;
+	}
+	
+	/**
+	 * 设置:角色ID
+	 * @param roleId 角色ID
+	 */
+	public void setRoleId(Long roleId) {
+		this.roleId = roleId;
+	}
+
+	/**
+	 * 获取:角色ID
+	 * @return Long
+	 */
+	public Long getRoleId() {
+		return roleId;
+	}
+	
+}

+ 70 - 0
src/main/java/io/renren/modules/sys/entity/SysUserTokenEntity.java

@@ -0,0 +1,70 @@
+package io.renren.modules.sys.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 系统用户Token
+ */
+public class SysUserTokenEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+	
+	//用户ID
+	private Long userId;
+	//token
+	private String token;
+	//过期时间
+	private Date expireTime;
+	//更新时间
+	private Date updateTime;
+
+	/**
+	 * 设置:用户ID
+	 */
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+	/**
+	 * 获取:用户ID
+	 */
+	public Long getUserId() {
+		return userId;
+	}
+	/**
+	 * 设置:token
+	 */
+	public void setToken(String token) {
+		this.token = token;
+	}
+	/**
+	 * 获取:token
+	 */
+	public String getToken() {
+		return token;
+	}
+	/**
+	 * 设置:过期时间
+	 */
+	public void setExpireTime(Date expireTime) {
+		this.expireTime = expireTime;
+	}
+	/**
+	 * 获取:过期时间
+	 */
+	public Date getExpireTime() {
+		return expireTime;
+	}
+	/**
+	 * 设置:更新时间
+	 */
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+	/**
+	 * 获取:更新时间
+	 */
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+}

+ 92 - 0
src/main/java/io/renren/modules/sys/oauth2/OAuth2Filter.java

@@ -0,0 +1,92 @@
+package io.renren.modules.sys.oauth2;
+
+import com.google.gson.Gson;
+import io.renren.common.utils.R;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpStatus;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * oauth2过滤器
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-05-20 13:00
+ */
+public class OAuth2Filter extends AuthenticatingFilter {
+
+    @Override
+    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
+        //获取请求token
+        String token = getRequestToken((HttpServletRequest) request);
+
+        if(StringUtils.isBlank(token)){
+            return null;
+        }
+
+        return new OAuth2Token(token);
+    }
+
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+        return false;
+    }
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        //获取请求token,如果token不存在,直接返回401
+        String token = getRequestToken((HttpServletRequest) request);
+        if(StringUtils.isBlank(token)){
+            HttpServletResponse httpResponse = (HttpServletResponse) response;
+            String json = new Gson().toJson(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));
+            httpResponse.getWriter().print(json);
+
+            return false;
+        }
+
+        return executeLogin(request, response);
+    }
+
+    @Override
+    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
+        HttpServletResponse httpResponse = (HttpServletResponse) response;
+        httpResponse.setContentType("application/json;charset=utf-8");
+        try {
+            //处理登录失败的异常
+            Throwable throwable = e.getCause() == null ? e : e.getCause();
+            R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());
+
+            String json = new Gson().toJson(r);
+            httpResponse.getWriter().print(json);
+        } catch (IOException e1) {
+
+        }
+
+        return false;
+    }
+
+    /**
+     * 获取请求的token
+     */
+    private String getRequestToken(HttpServletRequest httpRequest){
+        //从header中获取token
+        String token = httpRequest.getHeader("token");
+
+        //如果header中不存在token,则从参数中获取token
+        if(StringUtils.isBlank(token)){
+            token = httpRequest.getParameter("token");
+        }
+
+        return token;
+    }
+
+
+}

+ 73 - 0
src/main/java/io/renren/modules/sys/oauth2/OAuth2Realm.java

@@ -0,0 +1,73 @@
+package io.renren.modules.sys.oauth2;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.entity.SysUserTokenEntity;
+import io.renren.modules.sys.service.ShiroService;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Set;
+
+/**
+ * 认证
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-05-20 14:00
+ */
+@Component
+public class OAuth2Realm extends AuthorizingRealm {
+    @Autowired
+    private ShiroService shiroService;
+
+    @Override
+    public boolean supports(AuthenticationToken token) {
+        return token instanceof OAuth2Token;
+    }
+
+    /**
+     * 授权(验证权限时调用)
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
+        Long userId = user.getUserId();
+
+        //用户权限列表
+        Set<String> permsSet = shiroService.getUserPermissions(userId);
+
+        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+        info.setStringPermissions(permsSet);
+        return info;
+    }
+
+    /**
+     * 认证(登录时调用)
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+        String accessToken = (String) token.getPrincipal();
+
+        //根据accessToken,查询用户信息
+        SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);
+        //token失效
+        if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
+            throw new IncorrectCredentialsException("token失效,请重新登录");
+        }
+
+        //查询用户信息
+        SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());
+        //账号锁定
+        if(user.getStatus() == 0){
+            throw new LockedAccountException("账号已被锁定,请联系管理员");
+        }
+
+        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
+        return info;
+    }
+}

+ 29 - 0
src/main/java/io/renren/modules/sys/oauth2/OAuth2Token.java

@@ -0,0 +1,29 @@
+package io.renren.modules.sys.oauth2;
+
+
+import org.apache.shiro.authc.AuthenticationToken;
+
+/**
+ * token
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-05-20 13:22
+ */
+public class OAuth2Token implements AuthenticationToken {
+    private String token;
+
+    public OAuth2Token(String token){
+        this.token = token;
+    }
+
+    @Override
+    public String getPrincipal() {
+        return token;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return token;
+    }
+}

+ 46 - 0
src/main/java/io/renren/modules/sys/oauth2/TokenGenerator.java

@@ -0,0 +1,46 @@
+package io.renren.modules.sys.oauth2;
+
+import io.renren.common.exception.RRException;
+
+import java.security.MessageDigest;
+import java.util.UUID;
+
+/**
+ * 生成token
+ *
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-05-20 14:41
+ */
+public class TokenGenerator {
+
+    public static String generateValue() {
+        return generateValue(UUID.randomUUID().toString());
+    }
+
+    private static final char[] hexCode = "0123456789abcdef".toCharArray();
+
+    public static String toHexString(byte[] data) {
+        if(data == null) {
+            return null;
+        }
+        StringBuilder r = new StringBuilder(data.length*2);
+        for ( byte b : data) {
+            r.append(hexCode[(b >> 4) & 0xF]);
+            r.append(hexCode[(b & 0xF)]);
+        }
+        return r.toString();
+    }
+
+    public static String generateValue(String param) {
+        try {
+            MessageDigest algorithm = MessageDigest.getInstance("MD5");
+            algorithm.reset();
+            algorithm.update(param.getBytes());
+            byte[] messageDigest = algorithm.digest();
+            return toHexString(messageDigest);
+        } catch (Exception e) {
+            throw new RRException("生成Token失败", e);
+        }
+    }
+}

+ 27 - 0
src/main/java/io/renren/modules/sys/service/ShiroService.java

@@ -0,0 +1,27 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.entity.SysUserTokenEntity;
+
+import java.util.Set;
+
+/**
+ * shiro相关接口
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-06-06 8:49
+ */
+public interface ShiroService {
+    /**
+     * 获取用户权限列表
+     */
+    Set<String> getUserPermissions(long userId);
+
+    SysUserTokenEntity queryByToken(String token);
+
+    /**
+     * 根据用户ID,查询用户
+     * @param userId
+     */
+    SysUserEntity queryUser(Long userId);
+}

+ 63 - 0
src/main/java/io/renren/modules/sys/service/SysConfigService.java

@@ -0,0 +1,63 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysConfigEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 系统配置信息
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年12月4日 下午6:49:01
+ */
+public interface SysConfigService {
+	
+	/**
+	 * 保存配置信息
+	 */
+	public void save(SysConfigEntity config);
+	
+	/**
+	 * 更新配置信息
+	 */
+	public void update(SysConfigEntity config);
+	
+	/**
+	 * 根据key,更新value
+	 */
+	public void updateValueByKey(String key, String value);
+	
+	/**
+	 * 删除配置信息
+	 */
+	public void deleteBatch(Long[] ids);
+	
+	/**
+	 * 获取List列表
+	 */
+	public List<SysConfigEntity> queryList(Map<String, Object> map);
+	/**
+	 * 获取总记录数
+	 */
+	public int queryTotal(Map<String, Object> map);
+	
+	public SysConfigEntity queryObject(Long id);
+	
+	/**
+	 * 根据key,获取配置的value值
+	 * 
+	 * @param key           key
+	 * @param defaultValue  缺省值
+	 */
+	public String getValue(String key, String defaultValue);
+	
+	/**
+	 * 根据key,获取value的Object对象
+	 * @param key    key
+	 * @param clazz  Object对象
+	 */
+	public <T> T getConfigObject(String key, Class<T> clazz);
+	
+}

+ 30 - 0
src/main/java/io/renren/modules/sys/service/SysLogService.java

@@ -0,0 +1,30 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysLogEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 系统日志
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-08 10:40:56
+ */
+public interface SysLogService {
+	
+	SysLogEntity queryObject(Long id);
+	
+	List<SysLogEntity> queryList(Map<String, Object> map);
+	
+	int queryTotal(Map<String, Object> map);
+	
+	void save(SysLogEntity sysLog);
+	
+	void update(SysLogEntity sysLog);
+	
+	void delete(Long id);
+	
+	void deleteBatch(Long[] ids);
+}

+ 69 - 0
src/main/java/io/renren/modules/sys/service/SysMenuService.java

@@ -0,0 +1,69 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysMenuEntity;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 菜单管理
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:42:16
+ */
+public interface SysMenuService {
+	
+	/**
+	 * 根据父菜单,查询子菜单
+	 * @param parentId 父菜单ID
+	 * @param menuIdList  用户菜单ID
+	 */
+	List<SysMenuEntity> queryListParentId(Long parentId, List<Long> menuIdList);
+	
+	/**
+	 * 获取不包含按钮的菜单列表
+	 */
+	List<SysMenuEntity> queryNotButtonList();
+	
+	/**
+	 * 获取用户菜单列表
+	 */
+	List<SysMenuEntity> getUserMenuList(Long userId);
+	
+	/**
+	 * 查询菜单
+	 */
+	SysMenuEntity queryObject(Long menuId);
+	
+	/**
+	 * 查询菜单列表
+	 */
+	List<SysMenuEntity> queryList(Map<String, Object> map);
+	
+	/**
+	 * 查询总数
+	 */
+	int queryTotal(Map<String, Object> map);
+	
+	/**
+	 * 保存菜单
+	 */
+	void save(SysMenuEntity menu);
+	
+	/**
+	 * 修改
+	 */
+	void update(SysMenuEntity menu);
+	
+	/**
+	 * 删除
+	 */
+	void deleteBatch(Long[] menuIds);
+	
+	/**
+	 * 查询用户的权限列表
+	 */
+	List<SysMenuEntity> queryUserList(Long userId);
+}

+ 23 - 0
src/main/java/io/renren/modules/sys/service/SysRoleMenuService.java

@@ -0,0 +1,23 @@
+package io.renren.modules.sys.service;
+
+import java.util.List;
+
+
+
+/**
+ * 角色与菜单对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:42:30
+ */
+public interface SysRoleMenuService {
+	
+	void saveOrUpdate(Long roleId, List<Long> menuIdList);
+	
+	/**
+	 * 根据角色ID,获取菜单ID列表
+	 */
+	List<Long> queryMenuIdList(Long roleId);
+	
+}

+ 34 - 0
src/main/java/io/renren/modules/sys/service/SysRoleService.java

@@ -0,0 +1,34 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysRoleEntity;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 角色
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:42:52
+ */
+public interface SysRoleService {
+	
+	SysRoleEntity queryObject(Long roleId);
+	
+	List<SysRoleEntity> queryList(Map<String, Object> map);
+	
+	int queryTotal(Map<String, Object> map);
+	
+	void save(SysRoleEntity role);
+	
+	void update(SysRoleEntity role);
+	
+	void deleteBatch(Long[] roleIds);
+	
+	/**
+	 * 查询用户创建的角色ID列表
+	 */
+	List<Long> queryRoleIdList(Long createUserId);
+}

+ 24 - 0
src/main/java/io/renren/modules/sys/service/SysUserRoleService.java

@@ -0,0 +1,24 @@
+package io.renren.modules.sys.service;
+
+import java.util.List;
+
+
+
+/**
+ * 用户与角色对应关系
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:43:24
+ */
+public interface SysUserRoleService {
+	
+	void saveOrUpdate(Long userId, List<Long> roleIdList);
+	
+	/**
+	 * 根据用户ID,获取角色ID列表
+	 */
+	List<Long> queryRoleIdList(Long userId);
+	
+	void delete(Long userId);
+}

+ 73 - 0
src/main/java/io/renren/modules/sys/service/SysUserService.java

@@ -0,0 +1,73 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysUserEntity;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 系统用户
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2016年9月18日 上午9:43:39
+ */
+public interface SysUserService {
+
+	/**
+	 * 查询用户的所有权限
+	 * @param userId  用户ID
+	 */
+	List<String> queryAllPerms(Long userId);
+	
+	/**
+	 * 查询用户的所有菜单ID
+	 */
+	List<Long> queryAllMenuId(Long userId);
+
+	/**
+	 * 根据用户名,查询系统用户
+	 */
+	SysUserEntity queryByUserName(String username);
+	
+	/**
+	 * 根据用户ID,查询用户
+	 * @param userId
+	 * @return
+	 */
+	SysUserEntity queryObject(Long userId);
+	
+	/**
+	 * 查询用户列表
+	 */
+	List<SysUserEntity> queryList(Map<String, Object> map);
+	
+	/**
+	 * 查询总数
+	 */
+	int queryTotal(Map<String, Object> map);
+	
+	/**
+	 * 保存用户
+	 */
+	void save(SysUserEntity user);
+	
+	/**
+	 * 修改用户
+	 */
+	void update(SysUserEntity user);
+	
+	/**
+	 * 删除用户
+	 */
+	void deleteBatch(Long[] userIds);
+	
+	/**
+	 * 修改密码
+	 * @param userId       用户ID
+	 * @param password     原密码
+	 * @param newPassword  新密码
+	 */
+	int updatePassword(Long userId, String password, String newPassword);
+}

+ 29 - 0
src/main/java/io/renren/modules/sys/service/SysUserTokenService.java

@@ -0,0 +1,29 @@
+package io.renren.modules.sys.service;
+
+import io.renren.modules.sys.entity.SysUserTokenEntity;
+import io.renren.common.utils.R;
+
+/**
+ * 用户Token
+ * 
+ * @author chenshun
+ * @email sunlightcs@gmail.com
+ * @date 2017-03-23 15:22:07
+ */
+public interface SysUserTokenService {
+
+	SysUserTokenEntity queryByUserId(Long userId);
+
+	SysUserTokenEntity queryByToken(String token);
+	
+	void save(SysUserTokenEntity token);
+	
+	void update(SysUserTokenEntity token);
+
+	/**
+	 * 生成token
+	 * @param userId  用户ID
+	 */
+	R createToken(long userId);
+
+}

+ 60 - 0
src/main/java/io/renren/modules/sys/service/impl/ShiroServiceImpl.java

@@ -0,0 +1,60 @@
+package io.renren.modules.sys.service.impl;
+
+import io.renren.common.utils.Constant;
+import io.renren.modules.sys.dao.SysMenuDao;
+import io.renren.modules.sys.dao.SysUserDao;
+import io.renren.modules.sys.dao.SysUserTokenDao;
+import io.renren.modules.sys.entity.SysMenuEntity;
+import io.renren.modules.sys.entity.SysUserEntity;
+import io.renren.modules.sys.entity.SysUserTokenEntity;
+import io.renren.modules.sys.service.ShiroService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+public class ShiroServiceImpl implements ShiroService {
+    @Autowired
+    private SysMenuDao sysMenuDao;
+    @Autowired
+    private SysUserDao sysUserDao;
+    @Autowired
+    private SysUserTokenDao sysUserTokenDao;
+
+    @Override
+    public Set<String> getUserPermissions(long userId) {
+        List<String> permsList;
+
+        //系统管理员,拥有最高权限
+        if(userId == Constant.SUPER_ADMIN){
+            List<SysMenuEntity> menuList = sysMenuDao.queryList(new HashMap<>());
+            permsList = new ArrayList<>(menuList.size());
+            for(SysMenuEntity menu : menuList){
+                permsList.add(menu.getPerms());
+            }
+        }else{
+            permsList = sysUserDao.queryAllPerms(userId);
+        }
+        //用户权限列表
+        Set<String> permsSet = new HashSet<>();
+        for(String perms : permsList){
+            if(StringUtils.isBlank(perms)){
+                continue;
+            }
+            permsSet.addAll(Arrays.asList(perms.trim().split(",")));
+        }
+        return permsSet;
+    }
+
+    @Override
+    public SysUserTokenEntity queryByToken(String token) {
+        return sysUserTokenDao.queryByToken(token);
+    }
+
+    @Override
+    public SysUserEntity queryUser(Long userId) {
+        return sysUserDao.queryObject(userId);
+    }
+}

+ 79 - 0
src/main/java/io/renren/modules/sys/service/impl/SysConfigServiceImpl.java

@@ -0,0 +1,79 @@
+package io.renren.modules.sys.service.impl;
+
+import com.google.gson.Gson;
+import io.renren.modules.sys.dao.SysConfigDao;
+import io.renren.modules.sys.entity.SysConfigEntity;
+import io.renren.modules.sys.service.SysConfigService;
+import io.renren.common.exception.RRException;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+
+@Service("sysConfigService")
+public class SysConfigServiceImpl implements SysConfigService {
+	@Autowired
+	private SysConfigDao sysConfigDao;
+	
+	@Override
+	@Transactional
+	public void save(SysConfigEntity config) {
+		sysConfigDao.save(config);
+	}
+
+	@Override
+	public void update(SysConfigEntity config) {
+		sysConfigDao.update(config);
+	}
+
+	@Override
+	public void updateValueByKey(String key, String value) {
+		sysConfigDao.updateValueByKey(key, value);
+	}
+
+	@Override
+	public void deleteBatch(Long[] ids) {
+		sysConfigDao.deleteBatch(ids);
+	}
+
+	@Override
+	public List<SysConfigEntity> queryList(Map<String, Object> map) {
+		return sysConfigDao.queryList(map);
+	}
+
+	@Override
+	public int queryTotal(Map<String, Object> map) {
+		return sysConfigDao.queryTotal(map);
+	}
+
+	@Override
+	public SysConfigEntity queryObject(Long id) {
+		return sysConfigDao.queryObject(id);
+	}
+
+	@Override
+	public String getValue(String key, String defaultValue) {
+		String value = sysConfigDao.queryByKey(key);
+		if(StringUtils.isBlank(value)){
+			return defaultValue;
+		}
+		return value;
+	}
+	
+	@Override
+	public <T> T getConfigObject(String key, Class<T> clazz) {
+		String value = getValue(key, null);
+		if(StringUtils.isNotBlank(value)){
+			return new Gson().fromJson(value, clazz);
+		}
+
+		try {
+			return clazz.newInstance();
+		} catch (Exception e) {
+			throw new RRException("获取参数失败");
+		}
+	}
+}

+ 54 - 0
src/main/java/io/renren/modules/sys/service/impl/SysLogServiceImpl.java

@@ -0,0 +1,54 @@
+package io.renren.modules.sys.service.impl;
+
+import io.renren.modules.sys.dao.SysLogDao;
+import io.renren.modules.sys.entity.SysLogEntity;
+import io.renren.modules.sys.service.SysLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+
+
+@Service("sysLogService")
+public class SysLogServiceImpl implements SysLogService {
+	@Autowired
+	private SysLogDao sysLogDao;
+	
+	@Override
+	public SysLogEntity queryObject(Long id){
+		return sysLogDao.queryObject(id);
+	}
+	
+	@Override
+	public List<SysLogEntity> queryList(Map<String, Object> map){
+		return sysLogDao.queryList(map);
+	}
+	
+	@Override
+	public int queryTotal(Map<String, Object> map){
+		return sysLogDao.queryTotal(map);
+	}
+	
+	@Override
+	public void save(SysLogEntity sysLog){
+		sysLogDao.save(sysLog);
+	}
+	
+	@Override
+	public void update(SysLogEntity sysLog){
+		sysLogDao.update(sysLog);
+	}
+	
+	@Override
+	public void delete(Long id){
+		sysLogDao.delete(id);
+	}
+	
+	@Override
+	public void deleteBatch(Long[] ids){
+		sysLogDao.deleteBatch(ids);
+	}
+	
+}

+ 0 - 0
src/main/java/io/renren/modules/sys/service/impl/SysMenuServiceImpl.java


Some files were not shown because too many files changed in this diff