当前位置:   article > 正文

Spring Security和ECharts实现权限控制、图形报表生成,Java,JavaScript,HTML源码

Spring Security和ECharts实现权限控制、图形报表生成,Java,JavaScript,HTML源码
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.       xmlns:context="http://www.springframework.org/schema/context"
  5.       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
  6.       xmlns:mvc="http://www.springframework.org/schema/mvc"
  7.       xmlns:security="http://www.springframework.org/schema/security"
  8.       xsi:schemaLocation="http://www.springframework.org/schema/beans
  9. http://www.springframework.org/schema/beans/spring-beans.xsd
  10. http://www.springframework.org/schema/mvc
  11. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  12. http://code.alibabatech.com/schema/dubbo
  13. http://code.alibabatech.com/schema/dubbo/dubbo.xsd
  14. http://www.springframework.org/schema/context
  15. http://www.springframework.org/schema/context/spring-context.xsd
  16.                          http://www.springframework.org/schema/security
  17.                          http://www.springframework.org/schema/security/spring-security.xsd">
  18.    <!--
  19.        http:用于定义相关权限控制
  20.        指定哪些资源不需要进行权限校验,可以使用通配符
  21.    -->
  22.    <security:http security="none" pattern="/js/**" />
  23.    <security:http security="none" pattern="/css/**" />
  24.    <security:http security="none" pattern="/img/**" />
  25.    <security:http security="none" pattern="/plugins/**" />
  26.  
  27.    <!--
  28.        http:用于定义相关权限控制
  29.        auto-config:是否自动配置
  30.                        设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等
  31.                        设置为false时需要显示提供登录表单配置,否则会报错
  32.        use-expressions:用于指定intercept-url中的access属性是否使用表达式
  33.    -->
  34.    <security:http auto-config="true" use-expressions="true">
  35.        <security:headers>
  36.            <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
  37.            <security:frame-options policy="SAMEORIGIN"></security:frame-options>
  38.        </security:headers>
  39.        <!--
  40.            intercept-url:定义一个拦截规则
  41.            pattern:对哪些url进行权限控制
  42.            access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,
  43.  请求的用户只需拥有其中的一个角色就能成功访问对应的URL
  44.            isAuthenticated():已经经过认证(不是匿名用户)
  45.        -->
  46.        <security:intercept-url pattern="/pages/**"  access="isAuthenticated()" />
  47.        <!--form-login:定义表单登录信息-->
  48.        <security:form-login login-page="/login.html"
  49.                             username-parameter="username"
  50.                             password-parameter="password"
  51.                             login-processing-url="/login.do"
  52.                             default-target-url="/pages/main.html"
  53.                             always-use-default-target="true"
  54.                             authentication-failure-url="/login.html"
  55.        />
  56.        
  57.        <!--
  58.            csrf:对应CsrfFilter过滤器
  59.            disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,
  60. 否则登录操作会被禁用(403
  61.        -->
  62.        <security:csrf disabled="true"></security:csrf>
  63.    </security:http>
  64.    <!--配置密码加密对象-->
  65.    <bean id="passwordEncoder"
  66.          class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
  67.    <!--认证管理器,用于处理认证操作-->
  68.    <security:authentication-manager>
  69.        <!--认证提供者,执行具体的认证逻辑-->
  70.        <security:authentication-provider user-service-ref="springSecurityUserService">
  71.            <!--指定密码加密策略-->
  72.            <security:password-encoder ref="passwordEncoder" />
  73.        </security:authentication-provider>
  74.    </security:authentication-manager>
  75.    <!--开启注解方式权限控制-->
  76.    <security:global-method-security pre-post-annotations="enabled" />
  77. </beans>

1. 在项目中应用Spring Security

在真正进行认证和授权之前需要对数据进行管理,即我们需要开发如下一些功能:

1、权限数据管理(增删改查)

2、菜单数据管理(增删改查)

3、角色数据管理(增删改查、角色关联权限、角色关联菜单)

4、用户数据管理(增删改查、用户关联角色)

1.1 导入Spring Security环境

第一步:在health_parent父工程的pom.xml中导入Spring Security的maven坐标

  1. <dependency>
  2.  <groupId>org.springframework.security</groupId>
  3.  <artifactId>spring-security-web</artifactId>
  4.  <version>${spring.security.version}</version>
  5. </dependency>
  6. <dependency>
  7.  <groupId>org.springframework.security</groupId>
  8.  <artifactId>spring-security-config</artifactId>
  9.  <version>${spring.security.version}</version>
  10. </dependency>

 

第二步:在health_backend工程的web.xml文件中配置用于整合Spring Security框架的过滤器DelegatingFilterProxy

  1. <!--委派过滤器,用于整合其他框架-->
  2. <filter>
  3.  <!--整合spring security时,此过滤器的名称固定springSecurityFilterChain-->
  4.  <filter-name>springSecurityFilterChain</filter-name>
  5.  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  6. </filter>
  7. <filter-mapping>
  8.  <filter-name>springSecurityFilterChain</filter-name>
  9.  <url-pattern>/*</url-pattern>
  10. </filter-mapping>

 

1.2 实现认证和授权

第一步:在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,并且实现UserDetailsService接口

  1. package com.test.security;
  2. import com.test.dubbo.config.annotation.Reference;
  3. import com.test.pojo.CheckItem;
  4. import com.test.pojo.Permission;
  5. import com.test.pojo.Role;
  6. import com.test.service.CheckItemService;
  7. import com.test.service.UserService;
  8. import org.springframework.security.core.GrantedAuthority;
  9. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  10. import org.springframework.security.core.userdetails.User;
  11. import org.springframework.security.core.userdetails.UserDetails;
  12. import org.springframework.security.core.userdetails.UserDetailsService;
  13. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  14. import org.springframework.stereotype.Component;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. import java.util.Set;
  18. @Component
  19. public class SpringSecurityUserService implements UserDetailsService{
  20.    @Reference //注意:此处要通过dubbo远程调用用户服务
  21.    private UserService userService;
  22.  
  23.    //根据用户名查询用户信息
  24.    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  25.     //远程调用用户服务,根据用户名查询用户信息
  26.        com.test.pojo.User user = userService.findByUsername(username);
  27.        if(user == null){
  28.              //用户名不存在
  29.              return null;
  30.       }
  31.        List<GrantedAuthority> list = new ArrayList<>();
  32.        Set<Role> roles = user.getRoles();
  33.        for(Role role : roles){
  34.            //授予角色
  35.            list.add(new SimpleGrantedAuthority(role.getKeyword()));
  36.            Set<Permission> permissions = role.getPermissions();
  37.            for(Permission permission : permissions){
  38.             //授权
  39.                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
  40.           }
  41.       }
  42.        
  43.        UserDetails userDetails = new User(username,user.getPassword(),list);
  44.        return userDetails;
  45.   }
  46. }

第二步:创建UserService服务接口、服务实现类、Dao接口、Mapper映射文件等

  1. package com.test.service;
  2. import com.test.pojo.User;
  3. /**
  4. * 用户服务接口
  5. */
  6. public interface UserService {
  7.    public User findByUsername(String username);
  8. }
  1. package com.test.service;
  2. import com.test.dubbo.config.annotation.Service;
  3. import com.test.dao.PermissionDao;
  4. import com.test.dao.RoleDao;
  5. import com.test.dao.UserDao;
  6. import com.test.pojo.Permission;
  7. import com.test.pojo.Role;
  8. import com.test.pojo.User;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.transaction.annotation.Transactional;
  11. import java.util.Set;
  12. @Service(interfaceClass = UserService.class)
  13. @Transactional
  14. public class UserServiceImpl implements UserService {
  15.    @Autowired
  16.    private UserDao userDao;
  17.    @Autowired
  18.    private RoleDao roleDao;
  19.    @Autowired
  20.    private PermissionDao permissionDao;
  21.    public User findByUsername(String username) {
  22.        User user = userDao.findByUsername(username);
  23.        if(user == null){
  24.            return null;
  25.       }
  26.        Integer userId = user.getId();
  27.        Set<Role> roles = roleDao.findByUserId(userId);
  28.        if(roles != null && roles.size() > 0){
  29.            for(Role role : roles){
  30.                Integer roleId = role.getId();
  31.                Set<Permission> permissions = permissionDao.findByRoleId(roleId);
  32.                if(permissions != null && permissions.size() > 0){
  33.                    role.setPermissions(permissions);
  34.               }
  35.           }
  36.            user.setRoles(roles);
  37.       }
  38.        return user;
  39.   }
  40. }
  1. package com.test.dao;
  2. import com.test.pojo.User;
  3. public interface UserDao {
  4.    public User findByUsername(String username);
  5. }
  1. package com.test.dao;
  2. import com.test.pojo.Role;
  3. import java.util.Set;
  4. public interface RoleDao {
  5.    public Set<Role> findByUserId(int id);
  6. }
  1. package com.test.dao;
  2. import com.test.pojo.Permission;
  3. import java.util.Set;
  4. public interface PermissionDao {
  5.    public Set<Permission> findByRoleId(int roleId);
  6. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3.        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  4. <mapper namespace="com.test.dao.UserDao" >
  5.    <select id="findByUsername"
  6.            parameterType="string"
  7.            resultType="com.test.pojo.User">
  8.       select * from t_user where username = #{username}
  9.    </select>
  10. </mapper>
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3.        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  4. <mapper namespace="com.test.dao.RoleDao" >
  5.    <select id="findByUserId"
  6.            parameterType="int"
  7.            resultType="com.test.pojo.Role">
  8.       select r.*
  9.     from t_role r ,t_user_role ur
  10.     where r.id = ur.role_id and ur.user_id = #{userId}
  11.    </select>
  12. </mapper>
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3.        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  4. <mapper namespace="com.test.dao.PermissionDao" >
  5.    <select id="findByRoleId"
  6.            parameterType="int"
  7.            resultType="com.test.pojo.Permission">
  8.       select p.*
  9.     from t_permission p ,t_role_permission rp
  10.     where p.id = rp.permission_id and rp.role_id = #{roleId}
  11.    </select>
  12. </mapper>
 

第三步:修改health_backend工程中的springmvc.xml文件,修改dubbo批量扫描的包路径

  1. <!--批量扫描-->
  2. <dubbo:annotation package="com.test" />

注意:此处原来扫描的包为com.test.controller,现在改为com.test包的目的是需要将我们上面定义的SpringSecurityUserService也扫描到,因为在SpringSecurityUserService的loadUserByUsername方法中需要通过dubbo远程调用名称为UserService的服务。

第四步:在health_backend工程中提供spring-security.xml配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.       xmlns:context="http://www.springframework.org/schema/context"
  5.       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
  6.       xmlns:mvc="http://www.springframework.org/schema/mvc"
  7.       xmlns:security="http://www.springframework.org/schema/security"
  8.       xsi:schemaLocation="http://www.springframework.org/schema/beans
  9. http://www.springframework.org/schema/beans/spring-beans.xsd
  10. http://www.springframework.org/schema/mvc
  11. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  12. http://code.alibabatech.com/schema/dubbo
  13. http://code.alibabatech.com/schema/dubbo/dubbo.xsd
  14. http://www.springframework.org/schema/context
  15. http://www.springframework.org/schema/context/spring-context.xsd
  16.                          http://www.springframework.org/schema/security
  17.                          http://www.springframework.org/schema/security/spring-security.xsd">
  18.    <!--
  19.        http:用于定义相关权限控制
  20.        指定哪些资源不需要进行权限校验,可以使用通配符
  21.    -->
  22.    <security:http security="none" pattern="/js/**" />
  23.    <security:http security="none" pattern="/css/**" />
  24.    <security:http security="none" pattern="/img/**" />
  25.    <security:http security="none" pattern="/plugins/**" />
  26.  
  27.    <!--
  28.        http:用于定义相关权限控制
  29.        auto-config:是否自动配置
  30.                        设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等
  31.                        设置为false时需要显示提供登录表单配置,否则会报错
  32.        use-expressions:用于指定intercept-url中的access属性是否使用表达式
  33.    -->
  34.    <security:http auto-config="true" use-expressions="true">
  35.        <security:headers>
  36.            <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
  37.            <security:frame-options policy="SAMEORIGIN"></security:frame-options>
  38.        </security:headers>
  39.        <!--
  40.            intercept-url:定义一个拦截规则
  41.            pattern:对哪些url进行权限控制
  42.            access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,
  43.  请求的用户只需拥有其中的一个角色就能成功访问对应的URL
  44.            isAuthenticated():已经经过认证(不是匿名用户)
  45.        -->
  46.        <security:intercept-url pattern="/pages/**"  access="isAuthenticated()" />
  47.        <!--form-login:定义表单登录信息-->
  48.        <security:form-login login-page="/login.html"
  49.                             username-parameter="username"
  50.                             password-parameter="password"
  51.                             login-processing-url="/login.do"
  52.                             default-target-url="/pages/main.html"
  53.                             always-use-default-target="true"
  54.                             authentication-failure-url="/login.html"
  55.        />
  56.        
  57.        <!--
  58.            csrf:对应CsrfFilter过滤器
  59.            disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,
  60. 否则登录操作会被禁用(403
  61.        -->
  62.        <security:csrf disabled="true"></security:csrf>
  63.    </security:http>
  64.    <!--配置密码加密对象-->
  65.    <bean id="passwordEncoder"
  66.          class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
  67.    <!--认证管理器,用于处理认证操作-->
  68.    <security:authentication-manager>
  69.        <!--认证提供者,执行具体的认证逻辑-->
  70.        <security:authentication-provider user-service-ref="springSecurityUserService">
  71.            <!--指定密码加密策略-->
  72.            <security:password-encoder ref="passwordEncoder" />
  73.        </security:authentication-provider>
  74.    </security:authentication-manager>
  75.    <!--开启注解方式权限控制-->
  76.    <security:global-method-security pre-post-annotations="enabled" />
  77. </beans>

第五步:在springmvc.xml文件中引入spring-security.xml文件

<import resource="spring-security.xml"></import>

第六步:在Controller的方法上加入权限控制注解,此处以CheckItemController为例

  1. package com.test.controller;
  2. import com.alibaba.dubbo.config.annotation.Reference;
  3. import com.test.constant.MessageConstant;
  4. import com.test.constant.PermissionConstant;
  5. import com.test.entity.PageResult;
  6. import com.test.entity.QueryPageBean;
  7. import com.test.entity.Result;
  8. import com.test.exception.CustomException;
  9. import com.test.pojo.CheckItem;
  10. import com.test.pojo.Member;
  11. import com.test.service.CheckItemService;
  12. import org.springframework.security.access.annotation.Secured;
  13. import org.springframework.security.access.prepost.PreAuthorize;
  14. import org.springframework.web.bind.annotation.RequestBody;
  15. import org.springframework.web.bind.annotation.RequestMapping;
  16. import org.springframework.web.bind.annotation.RequestParam;
  17. import org.springframework.web.bind.annotation.RestController;
  18. import org.springframework.web.multipart.commons.CommonsMultipartFile;
  19. import java.util.List;
  20. /**
  21. * 体检检查项管理
  22. */
  23. @RestController
  24. @RequestMapping("/checkitem")
  25. public class CheckItemController {
  26.    @Reference
  27.    private CheckItemService checkItemService;
  28.    //分页查询
  29.    @PreAuthorize("hasAuthority('CHECKITEM_QUERY')")//权限校验
  30.    @RequestMapping("/findPage")
  31.    public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
  32.        PageResult pageResult = checkItemService.pageQuery(
  33.                                    queryPageBean.getCurrentPage(),
  34.                                    queryPageBean.getPageSize(),
  35.                                    queryPageBean.getQueryString());
  36.        return pageResult;
  37.   }
  38.    //删除
  39.    @PreAuthorize("hasAuthority('CHECKITEM_DELETE')")//权限校验
  40.    @RequestMapping("/delete")
  41.    public Result delete(Integer id){
  42.        try {
  43.            checkItemService.delete(id);
  44.       }catch (RuntimeException e){
  45.            return new Result(false,e.getMessage());
  46.       }catch (Exception e){
  47.            return new Result(false, MessageConstant.DELETE_CHECKITEM_FAIL);
  48.       }
  49.        return new Result(true,MessageConstant.DELETE_CHECKITEM_SUCCESS);
  50.   }
  51.    //新增
  52.    @PreAuthorize("hasAuthority('CHECKITEM_ADD')")//权限校验
  53.    @RequestMapping("/add")
  54.    public Result add(@RequestBody CheckItem checkItem){
  55.        try {
  56.            checkItemService.add(checkItem);
  57.       }catch (Exception e){
  58.            return new Result(false,MessageConstant.ADD_CHECKITEM_FAIL);
  59.       }
  60.        return new Result(true,MessageConstant.ADD_CHECKITEM_SUCCESS);
  61.   }
  62.    //编辑
  63.    @PreAuthorize("hasAuthority('CHECKITEM_EDIT')")//权限校验
  64.    @RequestMapping("/edit")
  65.    public Result edit(@RequestBody CheckItem checkItem){
  66.        try {
  67.            checkItemService.edit(checkItem);
  68.       }catch (Exception e){
  69.            return new Result(false,MessageConstant.EDIT_CHECKITEM_FAIL);
  70.       }
  71.        return new Result(true,MessageConstant.EDIT_CHECKITEM_SUCCESS);
  72.   }
  73. }

第七步:修改页面,没有权限时提示信息设置,此处以checkitem.html中的handleDelete方法为例

  1. //权限不足提示
  2. showMessage(r){
  3.  if(r == 'Error: Request failed with status code 403'){
  4.    //权限不足
  5.    this.$message.error('无访问权限');
  6.    return;
  7. }else{
  8.    this.$message.error('未知错误');
  9.    return;
  10. }
  11. }
  12. // 删除
  13. handleDelete(row) {
  14.  this.$confirm('此操作将永久当前数据,是否继续?', '提示', {
  15.    type: 'warning'
  16. }).then(()=>{
  17.    //点击确定按钮执行此代码
  18.    axios.get("/checkitem/delete.do?id=" + row.id).then((res)=> {
  19.      if(!res.data.flag){
  20.        //删除失败
  21.        this.$message.error(res.data.message);
  22.     }else{
  23.        //删除成功
  24.        this.$message({
  25.          message: res.data.message,
  26.          type: 'success'
  27.       });
  28.        this.findPage();
  29.     }
  30.   }).catch((r)=>{
  31.      this.showMessage(r);
  32.   });
  33. }).catch(()=> {
  34.    //点击取消按钮执行此代码
  35.    this.$message('操作已取消');
  36. });
  37. }

1.3 显示用户名

前面我们已经完成了认证和授权操作,如果用户认证成功后需要在页面展示当前用户的用户名。Spring Security在认证成功后会将用户信息保存到框架提供的上下文对象中,所以此处我们就可以调用Spring Security框架提供的API获取当前用户的username并展示到页面上。

实现步骤:

第一步:在main.html页面中修改,定义username模型数据基于VUE的数据绑定展示用户名,发送ajax请求获取username

  1. <script>
  2.    new Vue({
  3.        el: '#app',
  4.        data:{
  5.            username:null,//用户名
  6.      menuList:[]
  7.       },
  8.        created(){
  9.            //发送请求获取当前登录用户的用户名
  10.            axios.get('/user/getUsername.do').then((response)=>{
  11.                this.username = response.data.data;
  12.           });
  13.       }
  14.   });
  15. </script>
  16. <div class="avatar-wrapper">
  17.  <img src="../img/user2-160x160.jpg" class="user-avatar">
  18.  <!--展示用户名-->
  19. {{username}}
  20. </div>

第二步:创建UserController并提供getUsername方法

  1. package com.test.controller;
  2. import com.test.constant.MessageConstant;
  3. import com.test.entity.Result;
  4. import org.springframework.security.core.context.SecurityContextHolder;
  5. import org.springframework.security.core.context.SecurityContextImpl;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. @RestController
  9. @RequestMapping("/user")
  10. public class UserController {
  11.    //获取当前登录用户的用户名
  12.    @RequestMapping("/getUsername")
  13.    public Result getUsername()throws Exception{
  14.        try{
  15.            org.springframework.security.core.userdetails.User user =
  16.                   (org.springframework.security.core.userdetails.User)
  17.                    SecurityContextHolder.getContext().getAuthentication().getPrincipal();
  18.            return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,user.getUsername());
  19.       }catch (Exception e){
  20.            return new Result(false, MessageConstant.GET_USERNAME_FAIL);
  21.       }
  22.   }
  23. }

通过debug调试可以看到Spring Security框架在其上下文中保存的用户相关信息:

1.4 用户退出

第一步:在main.html中提供的退出菜单上加入超链接

  1. <el-dropdown-item divided>
  2.  <span style="display:block;"><a href="/logout.do">退出</a></span>
  3. </el-dropdown-item>

第二步:在spring-security.xml文件中配置

  1. <!--
  2.  logout:退出登录
  3.  logout-url:退出登录操作对应的请求路径
  4.  logout-success-url:退出登录后的跳转页面
  5. -->
  6. <security:logout logout-url="/logout.do"
  7.                 logout-success-url="/login.html" invalidate-session="true"/>

2. 图形报表ECharts

2.1 ECharts简介

ECharts缩写来自Enterprise Charts,商业级数据图表,是百度的一个开源的使用JavaScript实现的数据可视化工具,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的矢量图形库 ZRender,提供直观、交互丰富、可高度个性化定制的数据可视化图表。

官网:https://echarts.baidu.com/

下载地址:https://echarts.baidu.com/download.html

2.2 5分钟上手ECharts

我们可以参考官方提供的5分钟上手ECharts文档感受一下ECharts的使用方式,地址如下:

https://www.echartsjs.com/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts

第一步:创建html页面并引入echarts.js文件

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.    <meta charset="utf-8">
  5.    <!-- 引入 ECharts 文件 -->
  6.    <script src="echarts.js"></script>
  7. </head>
  8. </html>

第二步:在页面中准备一个具备宽高的DOM容器。

  1. <body>
  2.    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
  3.    <div id="main" style="width: 600px;height:400px;"></div>
  4. </body>

第三步:通过echarts.init方法初始化一个 echarts 实例并通过setOption方法生成一个简单的柱状图

  1. <script type="text/javascript">
  2.  // 基于准备好的dom,初始化echarts实例
  3.  var myChart = echarts.init(document.getElementById('main'));
  4.  // 指定图表的配置项和数据
  5.  var option = {
  6.    title: {
  7.      text: 'ECharts 入门示例'
  8.   },
  9.    tooltip: {},
  10.    legend: {
  11.      data:['销量']
  12.   },
  13.    xAxis: {
  14.      data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
  15.   },
  16.    yAxis: {},
  17.    series: [{
  18.      name: '销量',
  19.      type: 'bar',
  20.      data: [5, 20, 36, 10, 10, 20]
  21.   }]
  22. };
  23. // 使用刚指定的配置项和数据显示图表。
  24. myChart.setOption(option);
  25. </script>

效果如下:

2.3 查看ECharts官方实例

ECharts提供了很多官方实例,我们可以通过这些官方实例来查看展示效果和使用方法。

官方实例地址:https://www.echartsjs.com/examples/

可以点击具体的一个图形会跳转到编辑页面,编辑页面左侧展示源码(js部分源码),右侧展示图表效果。

要查看完整代码可以点击右下角的Download按钮将完整页面下载到本地。

通过官方案例我们可以发现,使用ECharts展示图表效果,关键点在于确定此图表所需的数据格式,然后按照此数据格式提供数据就可以了,我们无须关注效果是如何渲染出来的。

在实际应用中,我们要展示的数据往往存储在数据库中,所以我们可以发送ajax请求获取数据库中的数据并转为图表所需的数据即可。

3. 会员数量折线图

3.1 需求分析

会员信息是体检机构的核心数据,其会员数量和增长数量可以反映出机构的部分运营情况。通过折线图可以直观的反映出会员数量的增长趋势。本章节我们需要展示过去一年时间内每个月的会员总数据量。展示效果如下图:

3.2 完善页面

会员数量折线图对应的页面为/pages/report_member.html。

3.2.1 导入ECharts库

第一步:将echarts.js文件复制到health_backend工程的plugins目录下

第二步:在report_member.html页面引入echarts.js文件

<script src="../plugins/echarts/echarts.js"></script>

3.2.2 参照官方实例导入折线图
  1. <div class="box">
  2.  <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
  3.  <div id="chart1" style="height:600px;"></div>
  4. </div>
  5. <script type="text/javascript">
  6.  // 基于准备好的dom,初始化echarts实例
  7.  var myChart1 = echarts.init(document.getElementById('chart1'));
  8.  //发送ajax请求获取动态数据
  9.  axios.get("/report/getMemberReport.do").then((res)=>{
  10.    myChart1.setOption(
  11.     {
  12.        title: {
  13.          text: '会员数量'
  14.       },
  15.        tooltip: {},
  16.        legend: {
  17.          data:['会员数量']
  18.       },
  19.        xAxis: {
  20.          data: res.data.data.months
  21.       },
  22.        yAxis: {
  23.          type:'value'
  24.       },
  25.        series: [{
  26.          name: '会员数量',
  27.          type: 'line',
  28.          data: res.data.data.memberCount
  29.       }]
  30.     });
  31. });
  32. </script>

根据折线图对数据格式的要求,我们发送ajax请求,服务端需要返回如下格式的数据:

  1. {
  2. "data":{
  3. "months":["2019.01","2019.02","2019.03","2019.04"],
  4. "memberCount":[3,4,8,10]
  5.   },
  6. "flag":true,
  7. "message":"获取会员统计数据成功"
  8. }

3.3 后台代码

3.3.1 Controller

在health_backend工程中创建ReportController并提供getMemberReport方法

  1. package com.test.controller;
  2. import com.test.dubbo.config.annotation.Reference;
  3. import com.test.constant.MessageConstant;
  4. import com.test.entity.Result;
  5. import com.test.pojo.Setmeal;
  6. import com.test.service.MemberService;
  7. import com.test.service.ReportService;
  8. import com.test.service.SetmealService;
  9. import com.test.utils.DateUtils;
  10. import org.apache.poi.xssf.usermodel.XSSFRow;
  11. import org.apache.poi.xssf.usermodel.XSSFSheet;
  12. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RestController;
  16. import javax.servlet.ServletOutputStream;
  17. import javax.servlet.http.HttpServletRequest;
  18. import javax.servlet.http.HttpServletResponse;
  19. import java.io.File;
  20. import java.io.FileInputStream;
  21. import java.io.FileOutputStream;
  22. import java.math.BigDecimal;
  23. import java.text.SimpleDateFormat;
  24. import java.util.*;
  25. /**
  26. * 统计报表
  27. */
  28. @RestController
  29. @RequestMapping("/report")
  30. public class ReportController {
  31.    @Reference
  32.    private MemberService memberService;
  33.    /**
  34.     * 会员数量统计
  35.     * @return
  36.     */
  37.    @RequestMapping("/getMemberReport")
  38.    public Result getMemberReport(){
  39.        Calendar calendar = Calendar.getInstance();
  40.        calendar.add(Calendar.MONTH,-12);//获得当前日期之前12个月的日期
  41.        List<String> list = new ArrayList<>();
  42.        for(int i=0;i<12;i++){
  43.            calendar.add(Calendar.MONTH,1);
  44.            list.add(new SimpleDateFormat("yyyy.MM").format(calendar.getTime()));
  45.       }
  46.        Map<String,Object> map = new HashMap<>();
  47.        map.put("months",list);
  48.        List<Integer> memberCount = memberService.findMemberCountByMonth(list);
  49.        map.put("memberCount",memberCount);
  50.        return new Result(true, MessageConstant.GET_MEMBER_NUMBER_REPORT_SUCCESS,map);
  51.   }
  52. }

3.3.2 服务接口

在MemberService服务接口中扩展方法findMemberCountByMonth

public List<Integer> findMemberCountByMonth(List<String> month);

3.2.3 服务实现类

在MemberServiceImpl服务实现类中实现findMemberCountByMonth方法

  1. //根据月份统计会员数量
  2. public List<Integer> findMemberCountByMonth(List<String> month) {
  3.  List<Integer> list = new ArrayList<>();
  4.  for(String m : month){
  5.    m = m + ".31";//格式:2019.04.31
  6.    Integer count = memberDao.findMemberCountBeforeDate(m);
  7.    list.add(count);
  8. }
  9.  return list;
  10. }

3.3.4 Dao接口

在MemberDao接口中扩展方法findMemberCountBeforeDate

public Integer findMemberCountBeforeDate(String date);

3.3.5 Mapper映射文件

在MemberDao.xml映射文件中提供SQL语句

  1. <!--根据日期统计会员数,统计指定日期之前的会员数-->
  2. <select id="findMemberCountBeforeDate" parameterType="string" resultType="int">
  3. select count(id) from t_member where regTime &lt;= #{value}
  4. </select>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/390428
推荐阅读
相关标签
  

闽ICP备14008679号