范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

一套简单的登录鉴权工具

  前言
  无论是SpringSecruity、Shiro,对于一些小项目来说都太过复杂,有些情况下我们就想使用简单的登录、鉴权功能,本文记录手写一套简单的登录、鉴权工具
  思路
  1、封装工具类,集成查询系统用户、系统角色,根据登录用户权限进行当前URL请求鉴权
  2、在拦截器中调用工具类进行鉴权,通过放行、不通过则抛出对应业务异常信息
  首先需要三张基础表:系统用户表、系统角色表、用户角色关联表 -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user`  (   `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id",   `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "昵称",   `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "账号",   `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "密码",   PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统用户表" ROW_FORMAT = Compact;  -- ---------------------------- -- Records of sys_user -- ---------------------------- INSERT INTO `sys_user` VALUES ("1", "系统管理员", "admin", "000000"); INSERT INTO `sys_user` VALUES ("2", "张三-部门经理", "zhangsan", "111111"); INSERT INTO `sys_user` VALUES ("3", "小芳-前台接待", "xiaofang", "222222");  -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role`  (   `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id",   `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "角色名称",   `role_menu` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT "角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联)",   `role_url` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT "角色URL访问权限",   PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统角色表" ROW_FORMAT = Compact;  -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES ("1", "管理员", "[{"menuName":"系统管理","menuPath":"/sys/xtgl"},{"menuName":"用户管理","menuPath":"/sys/yhgl"},{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/sys/*,/portal/mhgl,/getLoginUser"); INSERT INTO `sys_role` VALUES ("2", "部门领导", "[{"menuName":"用户管理","menuPath":"/sys/yhgl"},{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/sys/yhgl,/portal/mhgl,/getLoginUser"); INSERT INTO `sys_role` VALUES ("3", "普通员工", "[{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/portal/mhgl,/getLoginUser");  -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role`  (   `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id",   `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "用户id",   `role_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "角色id",   PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统用户-角色关联表" ROW_FORMAT = Compact;  -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES ("1", "1", "1"); INSERT INTO `sys_user_role` VALUES ("2", "1", "2"); INSERT INTO `sys_user_role` VALUES ("3", "1", "3"); INSERT INTO `sys_user_role` VALUES ("4", "2", "2"); INSERT INTO `sys_user_role` VALUES ("5", "3", "3");
  在工具类中定义三个实体类方便传参接参(如果嫌麻烦也可以直接使用Map对象),使用自定义DbUtil查询数据库表数据(此操作,应交由项目ORM框架负责)  代码编写
  DbUtil工具类package cn.huanzi.qch.util;  import java.sql.*; import java.util.ArrayList; import java.util.HashMap;  /**  * 原生jdbc操作数据库工具类  */ public class DbUtil {      //数据库连接:地址、用户名、密码     private final String url;     private final String username;     private final String password;      //Connection连接实例     private Connection connection;      public DbUtil(String url, String username, String password){         this.url = url;         this.username = username;         this.password = password;     }     public DbUtil(String url, String username, String password, String driver){         this(url,username,password);          //加载驱动         try {             /*                 同时需要引入相关驱动依赖                  1、MySQL:                 com.mysql.cj.jdbc.Driver                  2、Oracle:                 oracle.jdbc.driver.OracleDriver                  3、pgsql:                 org.postgresql.Driver               */             Class.forName(driver);         } catch (ClassNotFoundException e) {             e.printStackTrace();         }     }      /**      * 获取 Connection 连接      */     private Connection getConnection() {         if(connection == null){             try {                 connection= DriverManager.getConnection(url, username, password);                 connection.setAutoCommit(true);             } catch (SQLException e) {                 System.err.println("获取Connection连接异常...");                 e.printStackTrace();             }         }         return connection;     }      /**      * 设置是否自动提交事务      * 当需要进行批量带事务的操作时,关闭自动提交手动管理事务,将会大大提高效率!      */     public void setAutoCommit(boolean autoCommit){         try {             this.getConnection().setAutoCommit(autoCommit);         } catch (SQLException e) {             e.printStackTrace();         }     }      /**      * 关闭自动提交事务时,需要手动管理事务提交、回滚      */     public void commit(){         try {             this.getConnection().commit();         } catch (SQLException e) {             e.printStackTrace();         }     }     public void rollback(){         try {             this.getConnection().rollback();         } catch (SQLException e) {             e.printStackTrace();         }     }      /**      * 关闭 Connection 连接      */     public void close(){         if(connection != null){             try {                 connection.close();                 connection = null;             } catch (SQLException e) {                 System.err.println("关闭Connection连接异常...");                 e.printStackTrace();             }         }     }      /**      * 查询      * 查询语句      */     public ArrayList> find(String sql, Object[] params) {         ArrayList> list = new ArrayList<>();          //获取连接         Connection conn = this.getConnection();         PreparedStatement ps;         ResultSet rs;          try {             //设置SQL、以及参数             ps = conn.prepareStatement(sql);             if (params != null) {                 for (int i = 0; i < params.length; i++) {                     ps.setObject(i + 1, params[i]);                 }             }              //执行查询             rs = ps.executeQuery();              //获取查询结果             ResultSetMetaData rm = rs.getMetaData();             int columnCount = rm.getColumnCount();              //封装结果集             while (rs.next()) {                 HashMap map = new HashMap<>(columnCount);                 for (int i = 1; i <= columnCount; i++) {                     String name = rm.getColumnName(i).toLowerCase();                     Object value = rs.getObject(i);                      map.put(name,value);                 }                 list.add(map);             }          } catch (Exception e) {             System.err.println("执行 jdbcUtil.find() 异常...");             e.printStackTrace();         }          return list;     }     public HashMap findOne(String sql, Object[] params){         ArrayList> list = this.find(sql, params);         return list.size() > 0 ? list.get(0) : null;     }     public ArrayList> find(String sql) {         return this.find(sql,null);     }     public HashMap findOne(String sql) {         return this.findOne(sql,null);     }      /**      * 执行      * 新增/删除/更新 等SQL语句      */     public boolean execute(String sql, Object[] params){         boolean flag = false;          //获取连接         Connection conn = this.getConnection();         PreparedStatement ps;          try {             //设置SQL、以及参数             ps = conn.prepareStatement(sql);             if (params != null) {                 for (int i = 0; i < params.length; i++) {                     ps.setObject(i + 1, params[i]);                 }             }              //执行             flag = ps.execute();         } catch (SQLException e) {             System.err.println("执行 jdbcUtil.update() 异常...");             e.printStackTrace();         }          return flag;     }     public boolean execute(String sql){         return this.execute(sql,null);     } }
  SecurityUtil工具类package cn.huanzi.qch.util;  import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List;  /**  * 一套简单的登录、鉴权工具  */ public class SecurityUtil {      /**      * 单例模式-饿汉      */     private static final SecurityUtil instance = new SecurityUtil();     private SecurityUtil (){}     public static SecurityUtil getInstance() {         return instance;     }      /**      * 无需登录即可访问的URL      * PS:建议从配置文件读取      */     private static final String[] URLS = {             //登录页、登录请求、注销请求             "/loginPage",             "/login",             "/logout",              //静态资源,例如:js、css等             "/assets/**",              //一些特殊无需权限控制的地址、api             "/portal/index",     };      /**      * 用户角色信息一般情况下是不轻易更改,可以将结果存储到缓存对象      */     private static HashMap> userRoleMap = new HashMap<>(10);      //查询数据库操作,应交由项目ORM框架负责     private final DbUtil dbUtil = new DbUtil("jdbc:mysql://localhost/jfinal_demo","root","123456");      /**      * 鉴权中心      * PS:返回值类型有待商榷      */     public String auc(HttpServletRequest request){         //请求URL地址         String requestUri = request.getRequestURI();          SecurityUtil securityUtil = SecurityUtil.getInstance();          //是否为无需登录即可访问URL         if(SecurityUtil.checkUrl(requestUri,SecurityUtil.URLS)){             //允许访问!             return "SUCCEED";         }          //是否为登录用户         SecurityUtil.User loginUser = securityUtil.getLoginUser(request);         if(loginUser == null){             //未登录或登录凭证过期!             return "UNAUTHORIZED";         }          //该登录用户是否有权访问当前URL         if(!SecurityUtil.checkUrl(requestUri,securityUtil.getRoleUrlByUserId(loginUser.getId()))){             //抱歉,你无权限访问!             return "FORBIDDEN";         }          //允许访问!         return "SUCCEED";     }      /**      * 检查requestUri是否包含在urls中      */     public static boolean checkUrl(String requestUri,String[] urls){         //对/进行特殊处理         if("/".equals(requestUri) && !Arrays.asList(urls).contains(requestUri)){             return false;         }          String[] requestUris = requestUri.split("/");         for (String url : urls) {             if (check(requestUris, url.split("/"))) {                 return true;             }         }          return false;     }     private static boolean check(String[] requestUris,String[] urls){         for (int i1 = 0; i1 < requestUris.length; i1++) {             //判断长度             if (i1 >= urls.length){                 return false;             }              //处理/*、/**情况             if("**".equals(urls[i1])){                 return true;             }             if("*".equals(urls[i1])){                 continue;             }              //处理带后缀             if(requestUris[i1].contains(".") && urls[i1].contains(".")){                 String[] split = requestUris[i1].split(".");                 String[] split2 = urls[i1].split(".");                  // *.后缀的情况                 if("*".equals(split2[0]) && split[1].equals(split2[1])){                     return true;                 }             }              //不相等             if(!requestUris[i1].equals(urls[i1])){                 return false;             }          }          return true;     }      /**      * 从request设置、获取当前登录用户      * PS:登录用户可以放在session中,也可以做做成jwt      */     public void setLoginUser(HttpServletRequest request,User loginUser){         request.getSession().setAttribute("loginUser",loginUser);     }     public User getLoginUser(HttpServletRequest request){         return (User)request.getSession().getAttribute("loginUser");     }     public List getLoginUserRole(HttpServletRequest request){         User loginUser = this.getLoginUser(request);         return loginUser != null ? getRoleByUserId(loginUser.getId()) : null;     }      /**      * 根据用户id,获取用户允许访问URL      */     public String[] getRoleUrlByUserId(String userId){         StringBuilder roleUrl = new StringBuilder();         for (SecurityUtil.Role role : this.getRoleByUserId(userId)) {             roleUrl.append(",").append(role.getRoleUrl());         }         return roleUrl.toString().split(",");     }      /**      * 获取用户、用户角色      * PS:这些查询数据库操作,应交由项目ORM框架负责      */     public User getUserByUserNameAndPassword(String username,String password){         //PS:密码应该MD5加密后密文存储,匹配时先MD5加密后匹配,本例中存储的是明文,就不进行MD5加密了         User user = null;         HashMap map = dbUtil.findOne("select * from sys_user where user_name = ? and password = ?", new String[]{username, password});         if(map != null){             user = new User(map.get("id").toString(),map.get("nick_name").toString(),map.get("user_name").toString(),map.get("password").toString());         }          //关闭数据库连接         dbUtil.close();          return user;     }     public List getRoleByUserId(String userId){         //先从缓存中获取         List roles = userRoleMap.get(userId);         if(roles != null){             return roles;         }          //查询数据库         List roleList = null;         List> list = dbUtil.find("select r.* from sys_role r join sys_user_role ur on r.id = ur.role_id where ur.user_id = ?", new String[]{userId});         if(list != null){             roleList = new ArrayList<>(list.size());             for (HashMap map : list) {                 roleList.add(new Role(map.get("id").toString(),map.get("role_name").toString(),map.get("role_menu").toString(),map.get("role_url").toString()));             }         }          //关闭数据库连接         dbUtil.close();          //放到缓存中         userRoleMap.put(userId,roleList);          return roleList;     }      /*         3张基础表          sys_user 系统用户表             id        表id             nick_name 昵称             user_name 账号             password  密码          sys_role 系统角色表             id        表id             role_name 角色名称             role_menu 角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联)             role_url  角色URL访问权限          sys_user_role 系统用户-角色关联表             id      表id             user_id 用户id             role_id 角色id      */     public class User{         private String id;//表id         private String nickName;//昵称         private String userName;//账号         private String password;//密码          public User(String id, String nickName, String userName, String password) {             this.id = id;             this.nickName = nickName;             this.userName = userName;             this.password = password;         }          public String getId() {             return id;         }          public String getNickName() {             return nickName;         }          public String getUserName() {             return userName;         }          public String getPassword() {             return password;         }     }     public class Role{         private String id;//表id         private String RoleName;//角色名称         private String RoleMenu;//角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联)         private String RoleUrl;//角色URL访问权限          public Role(String id, String roleName, String roleMenu, String roleUrl) {             this.id = id;             RoleName = roleName;             RoleMenu = roleMenu;             RoleUrl = roleUrl;         }          public String getId() {             return id;         }          public String getRoleName() {             return RoleName;         }          public String getRoleMenu() {             return RoleMenu;         }          public String getRoleUrl() {             return RoleUrl;         }     }     public class UserRole{         private String id;//表id         private String UserId;//用户id         private String RoleId;//角色id     } }
  数据库目前用的是mysql,使用时要记得添加驱动依赖  SpringBoot整合  代码
  PS:我们自定义DbUtil工具类获取连接操作,SpringBoot项目需要带上时区、字符集参数jdbc:mysql://localhost/jfinal_demo?serverTimezone=GMT%2B8&characterEncoding=utf-8
  新建一个springboot项目或在我们的springBoot项目中随便挑一个来测试
  首先需要将springboot-exceptionhandler项目中自定义统一异常处理相关代码拷贝过来,方便捕获我们抛出的业务异常
  然后新建一个AccessAuthorityFilter拦截器/**  * SpringBoot测试鉴权拦截器  */ @WebFilter(filterName = "AccessAuthorityFilter",urlPatterns = {"/**"}) @ServletComponentScan @Component public class AccessAuthorityFilter implements Filter {     @Override     public void init(FilterConfig filterConfig) {      }      @Override     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {         //请求头         HttpServletRequest request = (HttpServletRequest) servletRequest;          SecurityUtil securityUtil = SecurityUtil.getInstance();          //鉴权中心         String auc = securityUtil.auc(request);         if("UNAUTHORIZED".equals(auc)){             throw new ServiceException(ErrorEnum.UNAUTHORIZED);         }         if("FORBIDDEN".equals(auc)){             throw new ServiceException(ErrorEnum.FORBIDDEN);         }          //执行         filterChain.doFilter(servletRequest, servletResponse);     }      @Override     public void destroy() {      } }
  写几个测试接口,包括login登录、logout注销等/**  * 测试接口  */ @RestController public class TestController {      /**      * 简单登录、注销、获取登录用户      */     @GetMapping("/login")     public String login(HttpServletRequest request,String username, String password){         SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User user = securityUtil.getUserByUserNameAndPassword(username, password);         if(user != null){             securityUtil.setLoginUser(request,user);             return "登录成功!";         }else{             return "账号或密码错误...";         }     }     @GetMapping("/logout")     public String logout(HttpServletRequest request){         SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User loginUser = securityUtil.getLoginUser(request);         securityUtil.setLoginUser(request,null);          return "注销成功!";     }     @GetMapping("/getLoginUser")     public HashMap getLoginUser(HttpServletRequest request){         SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User loginUser = securityUtil.getLoginUser(request);         List loginUserRole = securityUtil.getLoginUserRole(request);          HashMap map = new HashMap<>(2);         map.put("loginUser",loginUser);         map.put("loginUserRole",loginUserRole);         return map;     }      /**      * 登录、鉴权测试接口      */     @GetMapping("/sys/xtgl")     public String xtgl() {         return "系统管理...";     }     @GetMapping("/sys/yhgl")     public String yhgl() {         return "用户管理...";     }     @GetMapping("/portal/mhgl")     public String mhgl() {         return "网站门户管理...";     }     @GetMapping("/portal/index")     public String portalIndex() {         return "网站门户首页...";     } }
  效果
   未登录时,只有配置在无需登录即可访问的URL才能允许访问
  登录后,除了无需权限的URL,还可以访问角色允许访问的URL,注销后恢复登录前状态
  SpringBoot项目比较常规大家用的也比较多,代码就不上传了  JFinal整合  代码
  创建一个访问权限拦截器AccessAuthorityInterceptorpackage cn.huanzi.qch.interceptor;  import cn.huanzi.qch.common.model.ErrorEnum; import cn.huanzi.qch.common.model.ServiceException; import cn.huanzi.qch.util.SecurityUtil; import com.jfinal.aop.Interceptor; import com.jfinal.aop.Invocation; import com.jfinal.log.Log;  import javax.servlet.http.HttpServletRequest;  /**  * 访问权限拦截器  */ public class AccessAuthorityInterceptor implements Interceptor {     private static final Log log = Log.getLog(AccessAuthorityInterceptor.class);      @Override     public void intercept(Invocation invocation) {         //请求头         HttpServletRequest request = invocation.getController().getRequest();          SecurityUtil securityUtil = SecurityUtil.getInstance();          //鉴权中心         String auc = securityUtil.auc(request);         if("UNAUTHORIZED".equals(auc)){             throw new ServiceException(ErrorEnum.UNAUTHORIZED);         }         if("FORBIDDEN".equals(auc)){             throw new ServiceException(ErrorEnum.FORBIDDEN);         }          invocation.invoke();     } }
  AppConfig中注册拦截器/**  * API 引导式配置  */ public class AppConfig extends JFinalConfig {      //省略其他代码...          /**      * 配置路由      */     public void configRoute(Routes me) {         //省略其他代码...          // 此处配置 Routes 级别的拦截器,可配置多个         me.addInterceptor(new AccessAuthorityInterceptor());     }          //省略其他代码... }
  写几个测试接口,包括login登录、logout注销等/**  * 用户表 Controller  *  * 作者:Auto Generator By "huanzi-qch"  * 生成日期:2021-07-29 17:32:50  */ @Path(value = "/user",viewPath = "/user") public class UserController extends CommonController {     //省略其他代码...      /**      * 简单登录、注销、获取登录用户      */     @ActionKey("/login")     public void login() {         String username = get("username");         String password = get("password");          SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User user = securityUtil.getUserByUserNameAndPassword(username, password);         if(user != null){             securityUtil.setLoginUser(this.getRequest(),user);             renderText("登录成功!");         }else{             renderText("账号或密码错误...");         }     }     @ActionKey("/logout")     public void logout() {         SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User loginUser = securityUtil.getLoginUser(this.getRequest());         securityUtil.setLoginUser(this.getRequest(),null);          renderText("注销成功!");     }     @ActionKey("/getLoginUser")     public void getLoginUser() {         SecurityUtil securityUtil = SecurityUtil.getInstance();         SecurityUtil.User loginUser = securityUtil.getLoginUser(this.getRequest());         List loginUserRole = securityUtil.getLoginUserRole(this.getRequest());          HashMap map = new HashMap<>(2);         map.put("loginUser",loginUser);         map.put("loginUserRole",loginUserRole);         renderJson(map);     }      /**      * 登录、鉴权测试接口      */     @ActionKey("/sys/xtgl")     public void xtgl() {         renderText("系统管理...");     }     @ActionKey("/sys/yhgl")     public void yhgl() {         renderText("用户管理...");     }     @ActionKey("/portal/mhgl")     public void mhgl() {         renderText("网站门户管理...");     }     @ActionKey("/portal/index")     public void portalIndex() {         renderText("网站门户首页...");     } }  效果
  未登录时,只有配置在无需登录即可访问的URL才能允许访问
  登录后,除了无需权限的URL,还可以访问角色允许访问的URL,注销后恢复登录前状态
  JFinal项目的整合代码在我的jfinal-demo项目中:不想用Spring全家桶?试试这个国产JFinal框架  后记
  一套简单的登录、鉴权工具暂时先记录到这,后续再进行补充版权声明
  作者:huanzi-qch
  出处:https://www.cnblogs.com/huanzi-qch
  若标题中有"转载"字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.

OnePlusBudsZ2真无线耳塞的渲染图像和发布时间表曝光在发布令人印象深刻的OnePlusBudsZ和OnePlusBudsPro真无线耳机产品之后,该公司显然正在开发其继任者,新品将被命名为OnePlusBudsZ2。这将是该品牌的下配置小改体验微创新雷蛇巴塞利斯蛇V3鼠标怎么样?巴塞利斯蛇V2鼠标上市有一段时间了,近日,雷蛇将这款产品更新至RazerBasiliskV3巴塞利斯蛇V3游戏鼠标,它在老款巴塞利斯蛇鼠标的模具基础上小改,并加入性能更强的引擎,以小户型看片神器,极米NEWZ6X家用投影仪让生活更温馨有多久没有和家人在同一个屏幕下一起娱乐了呢?手机几乎占据了我们所有的生活空间,尤其是租房的年轻男女们,在大屏下一起看剧重拾温馨成了一个难题。今天要为大家介绍的极米NEWZ6X家用投国产芯片巨头干得真漂亮,高通骁龙888和骁龙888要被反超在全球移动芯片领域,高通拥有压倒性的优势。在华为被断供芯片之前,安卓机市场尚且还有麒麟芯片可以跟骁龙芯片抗衡,而如今华为麒麟芯片也几乎成为了绝唱,国内安卓机市场几乎成为了高通的盘中发布两个月跌至1999元,6nm旗舰芯120Hz直屏,为何却无人问津?大家都知道现在很多厂商都喜欢搞什么子品牌,为的就是细分市场好去吸引消费者,本体则可以冲上高端卖出更贵的价格,子品牌基本上都是主打性价比,今天我们就来聊聊近两年来势头迅猛的realm一款老少咸宜的相机!尼康Zfc在日本大受好评自尼康发布复古微单相机Zfc后,迅速成为摄影市场的新人王,大家对这款相机也有相当不俗的评价,而在日本本土市场,尼康Zfc的销量同样报捷,日经日前的报导表示,尼康Zfc是一款可以吸引变频空调和定频空调该如何选择?为什么我选定频空调家人都不开心现在的家用空调种类有中央空调和分体空调,而分体空调中又分为变频空调和定频空调。由于装修之初没有安装中央空调,现在只能安装分体空调,可是选择分体空调的时候遇到一大难题,不知该选变频空上海游戏公司抢人大战应届生年薪开到60万,游戏从业者迎来黄金时代?本文来源时代周报作者郑栩彤去年至今,游戏企业涨薪异常疯狂。最集中涨薪和抢人的是上海,最稀缺的岗位是制作人TA(技术美术)和引擎。在上海某些公司,应届生从事TA和引擎可拿五六十万年薪大学老师说没有写过一千行以上代码的程序就别想上大公司大学老师说没有写过一千行以上代码的程序就别想上大公司这种说法对吗?如果说一千行代码都没写过基本上说明你没有受过充分的训练,很难说你在编程上面到底有没有什么造诣。当然这句话并不是说你中国移动与中国广电喜结连理2分钟前中国移动与中国广电签署有关协议规定中移动先行承担约定范围内700M无线网络全部建设费用,并先行享有上述无线网络资产所有权,双方均享有700M无线网络使用权,中国广电在条件具设计模式5依赖倒转原则依赖倒转原则A。高层模块不应该依赖底层模块,两个都应该依赖抽象B。抽象不应该依赖细节,细节应该依赖于抽象说白了,就是要针对接口编程,不要对实现编程高层模块依赖底层模块的例子面向过程
微信充值话费扣款成功却没到账是怎么回事?微信充话费,好像不支付充联通的号码。上次我给家里人充的就不能到帐,后面款返回到我的微信零钱了。但是用微信充移动的很快就到了。后面我用淘宝充联通才成功,不过我没试过用支付充联通号码的电脑硬件什么时候才降价啊?现在就连显示器都涨价了?电脑配件大部由于芯片缺货,现在降价很难哦,cpu的价格很难降下来,一是整体缺货,而是有黄牛在炒作。内存的价格就跌了,因为确实很缺需求。ssd的需求与价格也显疲软,行情一片惨淡。中端华为和比亚迪合作能不能超越特斯拉?在电动汽车行业超越特斯拉有点难,几乎没有可能性。即使华为和比亚迪合作也很难。比亚迪有着制造电池的优势,但是与特斯拉和松下合作的电池性能并不明显。华为虽有强大的5G技术,在未来自动驾有人给你误充5000话费,要你还现金,你怎么办?我肯定不会还的让他去找警察告我我无条件配合警察以及运营商首先5000话费在我看来只需要4000多就能充值了其次5000块钱我拿去存小银行拿45的利率一个月就18的利息了我一个月话费618持币3000元,购买什么手机好?感谢您的阅读!618,持币3000元,购买什么手机好呢一直以来,我们都认为一款手机的好坏一定是多种因素共同作用的结果。而在3000元左右,实际上它的价格已经非常具有优势了,怎么选择想买部性能强影像效果又好的手机,五千左右有推荐吗?感谢您的阅读!想买部性能强影像效果又好的手机,五千左右有推荐吗?影像能力实际上对于很多人来说似乎已经变得非常的重要了。我们在选择一款手机的时候,特别是一些影像能力强的手机的时候,确在加密市场暴跌3000亿美元后,狗狗币卷土重来,马斯克能量有多大本周五,在亿万富翁埃隆马斯克的支持下,以及加密货币交易所Coinbase宣布即将上架狗狗币(Dogecoin)之后,狗狗币的价格今天飙升了近30。上周末,由于受到马斯克将在周六夜现涨疯了!狗狗币开发人员透露从2019年起就一直在与马斯克合作狗狗币暴涨55Coinbase将很快增加对狗狗币的支持FX168财经报社(北美)讯周五(5月14日),狗狗币开发人员尼克尔在采访中表示,他们从2019年起就一直在与马斯克合作,让这种加密货币成为比特币更便宜更环保的替代品。据估计,狗狗都喷三缸是原罪,怎么理想ONE成了年度销量冠军?如果用一句话来形容2020年的理想,那闷声发大财肯定是最适合了。2020年理想ONE一年终端销售量为33457辆,击败蔚来成为了2020年度的新能源SUV销量冠军,要知道理想只有理华为确定今年鸿蒙生态目标适配APP超300个近日,据知名数码博主爆料,6月起将会有一大批预装鸿蒙OS的设备登场。同时,华为2021年的目标为至少1016市场份额年底前完成2亿台推送超3亿装机量超300个适配App。这里最值得如果实体行业都关闭了,只剩下电商,是进步还是倒退?如果实体行业都关闭了,只剩下电商,是进步还是倒退?电商的出现,给人们提供了一种全新的购物方式。可以免去实体购物路程的烦恼,只需要在电脑平板手机端点击几下,心仪的商品就会有快递小哥为