new-->Project-->Spring Initralizr Group:com.zb Artifact:zbook springboot version:2.0.4css
將html
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>複製代碼
改爲前端
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>複製代碼
maven clean一下,右鍵ZbookApplication運行,項目就跑起來了,就是這麼簡單,真正作到了開箱即用。java
package com.zb.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HomeController { @RequestMapping("/") public String home(){ return "Hello, Zbook!"; } }複製代碼
注:RestController和Controller註解的區別是:RestController是返回的內容就是返回的內容,至關於加個@ResponseBody,而controller通常是返回的頁面mysql
此時打開網頁,輸入 http://localhost:8080/ 就會看到Hello,Zbook!jquery
上面的能夠看成是提供服務的接口,假設咱們要開發一個web應用,springboot默認是集成的thymleaf。 springboot是約定大於配置的,咱們來看看關於thymleaf的約定 (1)默認靜態文件(js,css,jpg等)放在resources下面的static文件夾下面 (2)頁面文件放在templates文件夾下面 咱們採用bootstrap來渲染頁面,以下圖git
login.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>登陸</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <form action="login_in" method="post" class="form-horizontal" role="form" > <div class="form-group"> <h2 class="col-sm-offset-5 col-sm-4">用戶登陸</h2> </div> <div class="form-group"> <label for="username" class="col-sm-offset-3 col-sm-2 control-label">用戶名:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="username" name="username" placeholder="請輸入用戶名" /> </div> </div> <div class="form-group"> <label for="password" class="col-sm-offset-3 col-sm-2 control-label">密碼:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="password" name="password" placeholder="請輸入密碼" /> </div> </div> <div class="form-group"> <div class="col-sm-offset-5 col-sm-4"> <button type="submit" class="btn btn-default">登陸</button> </div> </div> </form> </div> <script src="/js/jquery-2.2.1.min.js"></script> <script src="/js/bootstrap.min.js"></script> </body> </html>複製代碼
package com.zb.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class LoginController { @RequestMapping("/login") public String login(){ return "login"; } }複製代碼
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>複製代碼
重啓, http://localhost:8080/login 則會看到登陸頁面github
springboot的配置文件分爲兩種:application.properties和application.yml 咱們把它改爲application.yml這種更直觀web
spring: application: name: myspringboot output: ansi: enabled: always profiles: active: dev thymeleaf: encoding: UTF-8 prefix: classpath:/templates/ server: tomcat: uri-encoding: UTF-8 max-connections: 500 min-spare-threads: 25 max-threads: 300 accept-count: 200 port: 8080 mybatis: type-aliases-package: com.zb.mapper mapper-locations: classpath:mapping/*.xml pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true params: count=countSql logging: level: com.zb.mapper: debug --- #開發配置 spring: profiles: dev datasource: url: jdbc:mysql://localhost:3306/zb_db?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&useSSL=false username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20複製代碼
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>RELEASE</version> </dependency> <!-- 分頁插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.3</version> </dependency>複製代碼
CREATE datebase zb_db;複製代碼
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `mobile` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `sex` varchar(255) DEFAULT NULL, `nickname` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;複製代碼
insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(1, 'admin', '123456', '13918891675','mmc@163.com', '男', '管理員'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(2, 'lisi2', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(3, 'lisi3', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(4, 'lisi4', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(5, 'lisi5', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(6, 'lisi6', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(7, 'lisi7', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(8, 'lisi8', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(9, 'lisi9', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(10, 'lisi10', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(11, 'lisi11', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(12, 'lisi12', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(13, 'lisi13', '123456', '13918891675','mmc@163.com', 'm', 'lisi1'); insert into `user`(id, username, password, mobile, email,sex, nickname) VALUES(14, 'lisi14', '123456', '13918891675','mmc@163.com', 'm', 'lisi1');複製代碼
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- 數據庫驅動:選擇你的本地硬盤上面的數據庫驅動包--> <classPathEntry location="C:\Users\DELL\Downloads\mysql-connector-java-5.1.22-bin.jar"/> <context id="DB2Tables" targetRuntime="MyBatis3"> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自動生成的註釋 true:是 : false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--數據庫連接URL,用戶名、密碼 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1/zb_db" userId="root" password="123456"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成模型的包名和位置--> <javaModelGenerator targetPackage="com.zb.model" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- 生成映射文件的包名和位置--> <sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- 生成DAO的包名和位置--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.zb.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名--> <table tableName="role_permission" domainObjectName="RolePermission" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> </context> </generatorConfiguration>複製代碼
<!-- mybatis generator 自動生成代碼插件 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin>複製代碼
此時目錄結構ajax
mapper增長了幾個方法
@Select("Select * from user") List<User> selectAll(); @Select("Select * from user where username = #{username} and password = #{password}") User selectByUsernamePass(@Param("username") String username, @Param("password") String password); @Select("Select * from user where username = #{username}") User selectByUsername(@Param("username") String username);複製代碼
dao和service都是正常調用,下面是controller
package com.zb.controller; import com.github.pagehelper.PageInfo; import com.zb.model.User; import com.zb.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { @Autowired private UserService userService; @RequestMapping("/user") @ResponseBody public User getUserById(int id){ User user = userService.selectByPrimaryKey(id); return user; } @RequestMapping("/userlist") public String getUserList(Model model, PageInfo pageInfo){ int pageNum = (pageInfo.getPageNum() == 0)? 1 : pageInfo.getPageNum(); int pageSize = (pageInfo.getPageSize() == 0)? 10 : pageInfo.getPageSize(); PageInfo<User> result = userService.selectAll(pageNum, pageSize); model.addAttribute("users", result.getList()); model.addAttribute("pageInfo", result); return "userlist"; } @RequestMapping("/userdelete") public String userdelete(int id){ userService.deleteByPrimaryKey(id); return "redirect:/userlist"; } @RequestMapping("/useredit") public String useredit(int id, Model model){ User user = userService.selectByPrimaryKey(id); model.addAttribute("user", user); return "useredit"; } @RequestMapping(value = "/userupdateoradd", method = RequestMethod.POST) public String userUpdateOrAdd(User user){ if(user.getId() == 0){ userService.insertSelective(user); } else { userService.updateByPrimaryKeySelective(user); } return "redirect:/userlist"; } }複製代碼
頁面userlist.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>用戶管理</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div> <nav class="navbar navbar-default" role="navigation"> <div class="container-fluid"> <div> <ul class="nav navbar-nav" > <li><a href="/userlist">用戶管理</a></li> <li><a href="#">書籍管理</a></li> </ul> </div> </div> </nav> </div> <div> <h2>用戶管理</h2> <table width="100%" border="0" cellpadding="0" cellspacing="0" class="table_list"> <thead> <tr> <th width="20%">編號</th> <th width="20%">用戶名</th> <th width="20%">電子郵箱</th> <th width="20%">手機</th> <th width="20%">操做</th> </tr> </thead> <tbody> <tr th:each="user:${users}"> <td height="40px"><a th:text="${user.id}" data-toggle="modal" data-target="#myModal" onclick="values(this)"></a></td> <td th:text="${user.username}"></td> <td th:text="${user.email}"></td> <td th:text="${user.mobile}"></td> <td><a href="#" class="delete_a" th:value="${user.id}">刪除</a></td> </tr> </tbody> </table> </div> </div> <script src="/js/jquery-2.2.1.min.js"></script> <script src="/js/bootstrap.min.js"></script> </body> </html>複製代碼
@ComponentScan(basePackages = {"com.zb"}) @MapperScan("com.zb.mapper")複製代碼
service層
@Override public PageInfo<User> selectAll(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> users = userDao.selectAll(); PageInfo<User> pageInfo = new PageInfo<>(users); return pageInfo; }複製代碼
controller層
public String getUserList(Model model, PageInfo pageInfo){ int pageNum = (pageInfo.getPageNum() == 0)? 1 : pageInfo.getPageNum(); int pageSize = (pageInfo.getPageSize() == 0)? 10 : pageInfo.getPageSize(); PageInfo<User> result = userService.selectAll(pageNum, pageSize); model.addAttribute("users", result.getList()); model.addAttribute("pageInfo", result); return "userlist"; }複製代碼
頁面修改:
<div id="example" style="text-align: center"> <ul id="pageLimit"></ul> </div> <input type="hidden" id="pageNum" name="pageNum" th:value="${pageInfo.pageNum}" /> <input type="hidden" id="pages" name="pages" th:value="${pageInfo.pages}" />複製代碼
<script src="/js/bootstrap-paginator.min.js"></script> <script> $('#pageLimit').bootstrapPaginator({ currentPage: $("#pageNum").val(), totalPages: $("#pages").val(), size: "normal", bootstrapMajorVersion: 3, alignment: "right", numberOfPages: 5, itemTexts: function (type, page, current) { switch (type) { case "first": return "首頁"; case "prev": return "上一頁"; case "next": return "下一頁"; case "last": return "末頁"; case "page": return page; } }, onPageClicked: function (event, originalEvent, type, page){//給每一個頁眉綁定一個事件,其實就是ajax請求,其中page變量爲當前點擊的頁上的數字。 window.location.href = "userlist?pageNum=" + page; } }); $(function(){ $(".delete_a").click(function(){ var userId=$(this).attr("value"); if(confirm("確認刪除嗎?")){ window.location.href="/userdelete?id=" + userId; return ; } }); }); </script>複製代碼
此時目錄
此時重啓,輸入 http://localhost:8080/userlist 就會看到user列表,也能夠分頁。
package com.zb.filter; import com.zb.model.User; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebFilter(filterName = "sessionFilter",urlPatterns = {"/*"}) public class SessionFilter implements Filter { String NO_LOGIN = "您還未登陸"; String[] includeUrls = new String[]{"/login","/login_in"}; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; HttpSession session = request.getSession(); String url = request.getRequestURI(); boolean needFilter = isNeedFilter(url); //靜態資源放行 if(url.endsWith(".css")||url.endsWith(".js")||url.endsWith(".jpg") ||url.endsWith(".gif")||url.endsWith(".png")){ filterChain.doFilter(servletRequest, servletResponse); return; } if(!needFilter){ filterChain.doFilter(servletRequest, servletResponse); } else { User user = (User)session.getAttribute(session.getId()); if(user != null){ filterChain.doFilter(servletRequest, servletResponse); } else { String requestType = request.getHeader("X-Requested-With"); //判斷是不是ajax請求 if(requestType!=null && "XMLHttpRequest".equals(requestType)){ response.getWriter().write(this.NO_LOGIN); }else{ //重定向到登陸頁(須要在static文件夾下創建此html文件) response.sendRedirect(request.getContextPath()+"/login"); } return; } } } public boolean isNeedFilter(String uri) { for (String includeUrl : includeUrls) { if(includeUrl.equals(uri)) { return false; } } return true; } @Override public void destroy() { } }複製代碼
@ServletComponentScan複製代碼
package com.zb.controller; import com.zb.model.User; import com.zb.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller public class LoginController { @Autowired private UserService userService; @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping(value = "/login_in", method = RequestMethod.POST) public String login_in(User user, HttpServletRequest request, Model model){ User user1 = userService.validateUser(user.getUsername(), user.getPassword()); if(user1 == null){ return "login"; } HttpSession session = request.getSession(); session.setAttribute(session.getId(), user1); return "redirect:/userlist"; } @RequestMapping("/logout") public String logout(HttpServletRequest request){ request.getSession().removeAttribute(request.getSession().getId()); return "login"; } }複製代碼
如今就能夠簡單的登陸了
<div> <a href="logout" style="display: inline-block; float: right">退出</a> <p th:text="${#httpSession.getAttribute(#httpSession.getId()).username}" style="display: inline-block; float: right"></p> <p style="display: inline-block; float: right">您好,</p> </div>複製代碼
權限管理咱們使用如今比較流行的shiro,原理就不說了,直接說怎麼使用
<!--shiro權限--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>複製代碼
shiro須要5張表:用戶、角色、權限、用戶角色關聯表,角色權限關聯表 用戶表已創建,如今續建4張表
CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rolename` varchar(255) DEFAULT NULL, `description` varchar(255) DEFAULT NULL, `status` varchar(255) DEFAULT NULL, `create_time` DATE DEFAULT NULL, `update_time` DATE DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `permissionname` varchar(255) DEFAULT NULL, `resourceType` varchar(255) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, `permission` varchar(255) DEFAULT NULL, `status` varchar(255) DEFAULT NULL, `create_time` DATE DEFAULT NULL, `update_time` DATE DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` varchar(255) DEFAULT NULL, `role_id` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `role_permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` varchar(255) DEFAULT NULL, `permission_id` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;複製代碼
insert into `role`(id, rolename, description, status, create_time, update_time) VALUES (1, 'admin', '管理員', 'use', '2018-08-10', '2018-08-10'); insert into `role`(id, rolename, description, status, create_time, update_time) VALUES (2, 'manage', '經理', 'use', '2018-08-10', '2018-08-10'); insert into `role`(id, rolename, description, status, create_time, update_time) VALUES (3, 'user', '普通用戶', 'use', '2018-08-10', '2018-08-10'); INSERT INTO `permission` (id, permissionname, resourceType, url, permission, status, create_time, update_time) VALUES (1,'用戶管理','menu', 'userlist','user:list','use','2018-08-10', '2018-08-10'); INSERT INTO `permission` (id, permissionname, resourceType, url, permission, status, create_time, update_time) VALUES (2,'用戶修改','menu', 'useredit','user:edit','use','2018-08-10', '2018-08-10'); INSERT INTO `permission` (id, permissionname, resourceType, url, permission, status, create_time, update_time) VALUES (3,'用戶刪除','menu', 'userdelete','user:delete','use','2018-08-10', '2018-08-10'); INSERT INTO `user_role` (id, user_id, role_id) VALUES (1, 1 ,1); INSERT INTO `user_role` (id, user_id, role_id) VALUES (2, 1 ,2); INSERT INTO `user_role` (id, user_id, role_id) VALUES (3, 1 ,3); INSERT INTO `user_role` (id, user_id, role_id) VALUES (4, 2 ,2); INSERT INTO `user_role` (id, user_id, role_id) VALUES (5, 3 ,3); INSERT INTO `user_role` (id, user_id, role_id) VALUES (6, 4 ,3); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (1, 1, 1); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (2, 1, 2); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (3, 1, 3); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (4, 2, 1); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (5, 2, 2); INSERT INTO `role_permission` (id, role_id, permission_id) VALUES (6, 3, 1);複製代碼
package com.zb.shiro; import java.util.LinkedHashMap; import java.util.Map; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 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; /** * Shiro 配置 * Apache Shiro 核心經過 Filter 來實現,就好像SpringMvc 經過DispachServlet 來主控制同樣。 既然是使用 Filter 通常也就能猜到,是經過URL規則來進行過濾和權限校驗,因此咱們須要定義一系列關於URL的規則和訪問權限。 */ @Configuration public class ShiroConfiguration { private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class); @Bean public FilterRegistrationBean delegatingFilterProxy(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); proxy.setTargetBeanName("shiroFilter"); filterRegistrationBean.setFilter(proxy); return filterRegistrationBean; } /** * ShiroFilterFactoryBean 處理攔截資源文件問題。 * 注意:單獨一個ShiroFilterFactoryBean配置是或報錯的,覺得在 * 初始化ShiroFilterFactoryBean的時候須要注入:SecurityManager * Filter Chain定義說明 一、一個URL能夠配置多個Filter,使用逗號分隔 二、當設置多個過濾器時,所有驗證經過,才視爲經過 三、部分過濾器可指定參數,如perms,roles * */ @Bean("shiroFilter") public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){ logger.info("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //攔截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); //配置退出過濾器,其中的具體的退出代碼Shiro已經替咱們實現了 filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/*/*.js", "anon"); filterChainDefinitionMap.put("/*/*.css", "anon"); filterChainDefinitionMap.put("/login_in", "anon"); filterChainDefinitionMap.put("/login", "anon"); //<!-- 過濾鏈定義,從上向下順序執行,通常將 /**放在最爲下邊 -->:這是一個坑呢,一不當心代碼就很差使了; //<!-- authc:全部url都必須認證經過才能夠訪問; anon:全部url都均可以匿名訪問--> filterChainDefinitionMap.put("/**", "authc"); // 若是不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登陸成功後要跳轉的連接 shiroFilterFactoryBean.setSuccessUrl("/userlist"); //未受權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/login"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } @Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } /** * 開啓Shiro的註解(如@RequiresRoles,@RequiresPermissions),需藉助SpringAOP掃描使用Shiro註解的類,並在必要時進行安全邏輯驗證 * 配置如下兩個bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)便可實現此功能 * @return */ @Bean public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } /** * 開啓aop註解支持 * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }複製代碼
package com.zb.shiro; import com.zb.model.Permission; import com.zb.model.Role; import com.zb.model.User; import com.zb.service.UserService; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; 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.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; /** * 身份校驗覈心類; * * @version v.0.1 */ public class MyShiroRealm extends AuthorizingRealm{ private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class); private static String SALT = "mySlalt"; @Resource private UserService userService; /** * 認證信息.(身份驗證) * : * Authentication 是用來驗證用戶身份 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { logger.info("MyShiroRealm.doGetAuthenticationInfo()"); //獲取用戶的輸入的帳號. String username = (String)token.getPrincipal(); //經過username從數據庫中查找 User對象,若是找到,沒找到. //實際項目中,這裏能夠根據實際狀況作緩存,若是不作,Shiro本身也是有時間間隔機制,2分鐘內不會重複執行該方法 User user = userService.selectByUsername(username); logger.info("----->>userInfo=" + user.toString()); if(user == null){ return null; } /* * 獲取權限信息:這裏沒有進行實現, * 請自行根據UserInfo,Role,Permission進行實現; * 獲取以後能夠在前端for循環顯示全部連接; */ //userInfo.setPermissions(userService.findPermissions(user)); userService.findRoleAndPermissions(user); //帳號判斷; //加密方式; //交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配,若是以爲人家的很差能夠自定義實現 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user, //用戶名 user.getPassword(), //密碼 ByteSource.Util.bytes(user.getUsername() + SALT),//salt=username+salt getName() //realm name ); //明文: 若存在,將此用戶存放到登陸認證info中,無需本身作密碼對比,Shiro會爲咱們進行密碼對比校驗 // SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( // userInfo, //用戶名 // userInfo.getPassword(), //密碼 // getName() //realm name // ); return authenticationInfo; } /** * 此方法調用 hasRole,hasPermission的時候纔會進行回調. * * 權限信息.(受權): * 一、若是用戶正常退出,緩存自動清空; * 二、若是用戶非正常退出,緩存自動清空; * 三、若是咱們修改了用戶的權限,而用戶不退出系統,修改的權限沒法當即生效。 * (須要手動編程進行實現;放在service進行調用) * 在權限修改後調用realm中的方法,realm已經由spring管理,因此從spring中獲取realm實例, * 調用clearCached方法; * :Authorization 是受權訪問控制,用於對用戶進行的操做受權,證實該用戶是否容許進行當前操做,如訪問某個連接,某個資源文件等。 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { logger.info("權限配置-->MyShiroRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); User userInfo = (User)principals.getPrimaryPrincipal(); ///在認證成功以後返回. //設置角色信息. //支持 Set集合, //用戶的角色對應的全部權限 for(Role role:userInfo.getRoleList()){ authorizationInfo.addRole(role.getRolename()); for(Permission p:role.getPermissionList()){ authorizationInfo.addStringPermission(p.getPermission()); } } return authorizationInfo; } }複製代碼
@Select("select * from Role where id in (select role_id from user_role where user_id = #{userId})") List<Role> selectRoleByUserId(@Param("userId") int userId);複製代碼
@Select("select * from permission where id in (select permission_id from role_permission where role_id = #{roleId})") List<Permission> selectPermissionIdByRoleId(@Param("roleId") int roleId);複製代碼
修改登陸方法
@RequestMapping(value = "/login_in", method = RequestMethod.POST) public String login_in(User user, HttpServletRequest request, Model model){ User user1 = userService.validateUser(user.getUsername(), user.getPassword()); if(user1 == null){ return "login"; } // (1) session // HttpSession session = request.getSession(); // session.setAttribute(session.getId(), user1); // return "redirect:/userlist"; // (3) shiro String msg ; UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); token.setRememberMe(true); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); if (subject.isAuthenticated()) { //shiro 的session和request的session封裝的是一個,就是說兩個均可以 // request.getSession().setAttribute(request.getSession().getId(),user); subject.getSession().setAttribute(subject.getSession().getId(),user); return "redirect:/userlist"; } else { return "login"; } } catch (IncorrectCredentialsException e) { msg = "登陸密碼錯誤. Password for account " + token.getPrincipal() + " was incorrect."; model.addAttribute("message", msg); System.out.println(msg); } catch (ExcessiveAttemptsException e) { msg = "登陸失敗次數過多"; model.addAttribute("message", msg); System.out.println(msg); } catch (LockedAccountException e) { msg = "賬號已被鎖定. The account for username " + token.getPrincipal() + " was locked."; model.addAttribute("message", msg); System.out.println(msg); } catch (DisabledAccountException e) { msg = "賬號已被禁用. The account for username " + token.getPrincipal() + " was disabled."; model.addAttribute("message", msg); System.out.println(msg); } catch (ExpiredCredentialsException e) { msg = "賬號已過時. the account for username " + token.getPrincipal() + " was expired."; model.addAttribute("message", msg); System.out.println(msg); } catch (UnknownAccountException e) { msg = "賬號不存在. There is no user with username of " + token.getPrincipal(); model.addAttribute("message", msg); System.out.println(msg); } catch (UnauthorizedException e) { msg = "您沒有獲得相應的受權!" + e.getMessage(); model.addAttribute("message", msg); System.out.println(msg); } return "login"; } @RequestMapping("/logout") public String logout(HttpServletRequest request){ // request.getSession().removeAttribute(request.getSession().getId()); SecurityUtils.getSubject().getSession().removeAttribute(SecurityUtils.getSubject().getSession().getId()); return "login"; }複製代碼
@RequestMapping("/userlist") @RequiresPermissions("user:list")複製代碼
@RequestMapping("/userdelete") @RequiresPermissions("user:delete")複製代碼
這種或者 頁面上
<shiro:hasPermission name="user:delete"></shiro:hasPermission>複製代碼
至此,權限就加好了