更新时间:2021年03月18日 08时58分24秒 来源:黑马程序员论坛
### 3.2 访问数据库实现用户认证 #### 3.2.1 表结构分析 系统数据库qingcheng_system .tb_admin 表(管理员表) | 字段名称 | 字段含义 | 字段类型 | 字段长度 | 备注 | | ---------- | -------- | -------- | -------- | ---- | | id | id | INT | | | | login_name | 用户名 | VARCHAR | | | | password | 密码 | VARCHAR | | | | status | 状态 | CHAR | | | #### 3.2.2 代码实现 修改UserDetailsServiceImpl ```java public class UserDetailsServiceImpl implements UserDetailsService { @Reference private AdminService adminService; public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { //查询管理员 Map map= new HashMap(); map.put("loginName",s); map.put("status","1"); List<Admin> list = adminService.findList(map); if(list.size()==0){ return null; } //构建角色集合 ,项目中此处应该是根据用户名查询用户的角色列表 List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>(); grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN")); return new User(s,list.get(0).getPassword(), grantedAuths); } } ``` ## 4. 青橙系统菜单展示 ### 4.1 需求分析 从数据库中读取菜单数据并展示。菜单为三级菜单,树形结构如下: ```json { "data": [ { "path": "1",//菜单项所对应的路由路径 "title": "首页", //菜单项名称 "icon":"iconHome",//是否有子菜单,若没有,则为[] }, { "path": "2", "title": "商品",//一级菜单 "icon":"iconCommodity", "children": [ { "path": "2-1", "title": "商品管理",//二级菜单 "linkUrl":"", "icon":"iconSp", "children":[ { "path": "2-1-1", "title": "商品列表", "linkUrl":"all-medical-list.html",//三级菜单 }, { "path": "2-1-2", "title": "添加商品", "linkUrl":"commodity-add.html", } ] }, { "path": "2-2", "title": "添加配置", "linkUrl":"", "icon":"iconSet", "children":[ { "path": "2-2-1", "title": "商品分类", "linkUrl":"all-medical-list.html", }, { "path": "2-2-2", "title": "规格参数", "linkUrl":"all-medical-list.html", } ] } ] } ] } ``` ### 4.2 表结构分析 tb_menu (菜单表) | 字段名称 | 字段含义 | 字段类型 | 字段长度 | 备注 | | --------- | ---------- | -------- | -------- | ---- | | id | 菜单ID | VARCHAR | | | | name | 菜单名称 | VARCHAR | | | | icon | 图标 | VARCHAR | | | | url | URL | VARCHAR | | | | parent_id | 上级菜单ID | VARCHAR | | | ### 4.3 代码实现 #### 4.3.1 后端代码 (1)MenuService接口新增方法定义,用于返回全部菜单 ```java public List<Map> findAllMenu(); ``` (2)MenuServiceImpl实现此方法 ```java /** * 查询全部菜单 * @return */ public List<Map> findAllMenu() { List<Menu> menuList = findAll();//查询全部菜单列表 return findMenuListByParentId(menuList,"0");//一级菜单列表 } /** * 查询下级菜单ID * @param menuList * @param parentId * @return */ private List<Map> findMenuListByParentId(List<Menu> menuList,String parentId){ List<Map> mapList=new ArrayList<>(); for(Menu menu:menuList){ //循环一级菜单 if(menu.getParentId().equals(parentId)){ Map map=new HashMap(); map.put("path",menu.getId()); map.put("title",menu.getName()); map.put("icon",menu.getIcon()); map.put("linkUrl",menu.getUrl()); map.put("children",findMenuListByParentId(menuList,menu.getId())); mapList.add(map); } } return mapList; } ``` (3)qingcheng_web_manager工程MenuController新增方法 ```java @GetMapping("/findMenu") public List<Map> findMenu(){ return menuService.findAllMenu(); } ``` #### 4.3.2 前端代码 修改页面的JS代码 ```js created() { //....... axios.get("/menu/findMenu.do").then( response=>{ this.menuList=response.data; this.data=response.data[0] var data=[] for(var i=0;i<response.data[0].children.length;i++){ data.push(response.data[0].children[i].path) } this.openeds=data }) } ``` #### 4.3.3 同源策略设置 由于我们的main.html是框架页,需要修改同源策略。 ```xml <headers> <frame-options policy="SAMEORIGIN"></frame-options> </headers> ``` *X-Frame-Options* response header 可用于指示是否应该允许浏览器呈现在一个页面(同源策略) **同源策略**限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。 解释一下同源。如果两个url,协议、地址和端口都相同,我们称两个url为同源。 Spring Security下,X-Frame-Options默认为DENY. 如果不修改同源策略,框架页内将无法显示内容。 DENY:浏览器拒绝当前页面加载任何Frame页面 SAMEORIGIN:frame页面的地址只能为同源域名下的页面 ALLOW-FROM:origin为允许frame加载的页面地址。 #### 4.3.4 获取当前登录人 需求:主界面显示当前登陆人 实现思路:后端编写controller输出当前登录人,前端异步调用。 (1)后端代码实现: ```java @RestController @RequestMapping("/login") public class LoginController { @GetMapping("/name") public Map showName(){ String name = SecurityContextHolder.getContext().getAuthentication().getName(); Map map=new HashMap(); map.put("name",name); return map; } } ``` (2)前端代码实现: 在main.html中添加属性loginName,用于存储当前的登陆人 created()方法添加代码 ```js //加载并显示当前登录名 axios.get('/login/name.do').then( response=>{ this.loginName= response.data.name; }) ``` 页面显示登陆人 ``` {{loginName}} ``` #### 4.3.5 退出登录 当我们在spring security配置文件中配置了`<logout/>`后,框架会为我们自动提供退出功能,地址为/logout,要求以post方式提交。 main.html新增方法 ```js exit(){ axios.post('/logout').then(response=>{ location.href="login.html"; }) } ``` 退出菜单调用: ```html <span style="display:block;" @click="exit()">退出</span> ``` ## 5. 管理员登录日志 ### 5.1 需求分析 管理员登录后,记录管理员名称、登录时间、ip、浏览器类型、所在地区等信息 。 ### 5.2 表结构分析 tb_login_log 表 | 字段名称 | 字段含义 | 字段类型 | 字段长度 | 备注 | | ------------ | ---------- | -------- | -------- | ---- | | id | id | INT | | | | login_name | 登录名 | VARCHAR | | | | ip | ip | VARCHAR | | | | browser_name | 浏览器类型 | VARCHAR | | | | location | 地区 | VARCHAR | | | | login_time | 登录时间 | DATETIME | | | ### 5.3 代码实现 #### 5.3.1 登录成功处理器 (1)spring security为我们提供了一个叫“登录成功处理器”的组件,我们可以实现在登录后进行的后续处理逻辑。 ```java public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { System.out.println("登录成功处理器到此一游"); request.getRequestDispatcher("/main.html").forward(request, response); } } ``` (2)applicationContext_security.xml新增配置 ```xml <beans:bean id="loginHandler" class="com.qingcheng.controller.AuthenticationSuccessHandlerImpl"> </beans:bean> ``` ```xml <!--设置登陆成功处理器--> <form-login login-page="/login.html" default-target-url="/main.html" authentication-failure-url="/login.html" authentication-success-handler-ref="loginHandler"/> ``` #### 5.3.2 登录日志处理 修改qingcheng_web_manager的AuthenticationSuccessHandlerImpl ```java public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { @Reference private LoginLogService loginLogService; @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { //登录后会调用 System.out.println("登录成功了,我要在这里记录日志"); String loginName = authentication.getName();//当前登录用户 String ip = httpServletRequest.getRemoteAddr(); //获取访问的ip LoginLog loginLog=new LoginLog(); loginLog.setLoginName(loginName); loginLog.setLoginTime(new Date()); // 当前登录时间 loginLog.setIp(ip); loginLogService.add(loginLog); httpServletRequest.getRequestDispatcher("/main.html").forward(httpServletRequest,httpServletResponse); } } ``` #### 5.3.3 根据IP获取城市信息 (1)将资源中提供的工具类WebUtil复制到qingcheng_common_web工程 (2)WebUtil类的getCityByIP用于根据IP地址获取城市信息,修改代码 ```java loginLog.setLocation(WebUtil.getCityByIP(ip));//保存城市信息 ``` #### 5.3.4 获取浏览器名称 |
推荐了解热门学科
java培训 | Python人工智能 | Web前端培训 | PHP培训 |
区块链培训 | 影视制作培训 | C++培训 | 产品经理培训 |
UI设计培训 | 新媒体培训 | 产品经理培训 | Linux运维 |
大数据培训 | 智能机器人软件开发 |
传智播客是一家致力于培养高素质软件开发人才的科技公司,“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。
传智播客从未停止思考
传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”
中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。
何为中高级程序员课程?
传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展。“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。
黑马程序员热门视频教程【点击播放】
Python入门教程完整版(懂中文就能学会) | 零起点打开Java世界的大门 |
C++| 匠心之作 从0到1入门学编程 | PHP|零基础入门开发者编程核心技术 |
Web前端入门教程_Web前端html+css+JavaScript | 软件测试入门到精通 |