派大星的博客

很多事情不是会了才能做,而是做了才能学会


  • 首页

  • 标签

  • 分类

  • 关于

  • 搜索

SpringBoot使用redis做分布式Session

发表于 2019-08-05 | 分类于 springboot

1. 核心原理

主要是通过redis,当用户登录后生成一个随机的uuid作为token,将token作为键,user对象作为值存储到redis数据库中,同时将token保存到cookie中 ,当访问其他页面时判断cookie中是否有token,如果有,则根据此token从redis拿到用户信息即可。

关于springboot 操作redis方面请查看 : https://blog.csdn.net/junmoxi/article/details/80694405

2. User服务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.pibigstar.springboot.service.impl;

import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.pibigstar.springboot.dao.JPADao;
import com.pibigstar.springboot.domain.User;
import com.pibigstar.springboot.service.RedisService;
import com.pibigstar.springboot.service.UserService;

@Service
public class UserServiceImpl implements UserService{

public static final String COOKIE_USER_TOKEN = "token";
public static final int COOKIE_TOKEN_TIMEOUT = 3600*24*2;//两天

@Autowired
private RedisService redisService;

/**
* 登录
* @param response
* @param loginVo
* @return
*/
@Override
public boolean login(HttpServletResponse response, LoginVo loginVo) {
if(loginVo == null) {
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
String mobile = loginVo.getMobile();
String formPass = loginVo.getPassword();
//判断手机号是否存在
User user = getById(Long.parseLong(mobile));
if(user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//验证密码
String dbPass = user.getPassword();
String saltDB = user.getSalt();
String calcPass = MD5Util.formPassToDBPass(formPass, saltDB);
if(!calcPass.equals(dbPass)) {
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
//生成cookie
String token = UUID.randomUUID().toString().replace("-", "");
addCookie(response, token, user);
return true;
}

/**
* 根据token从redis中拿到user对象
*/
@Override
public User getByToken(HttpServletResponse response, String token) {
if (token==null) {
return null;
}
User user = (User) redisService.getObject(token);
if (user!=null) {
//延长cookie有效期
addCookie(response,token,user);
}
return user;

}

/**
* 将token放到cookie中
* @param response
* @param token
* @param user
*/
private void addCookie(HttpServletResponse response, String token, User user) {
redisService.setObject(token, user,COOKIE_TOKEN_TIMEOUT);
Cookie cookie = new Cookie(COOKIE_USER_TOKEN, token);
//设置cookie有效期
cookie.setMaxAge(COOKIE_TOKEN_TIMEOUT);
cookie.setPath("/");
response.addCookie(cookie);
}
}

3. 读取cookie中的token

我们通过实现 HandlerMethodArgumentResolver 接口,重写里面的方法,将cookie中或者parameter中的token数据拿到然后查询出user注入到Controller中 的方法参数中

注册一个ArgumentResolvers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.pibigstar.springboot.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer{
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserArgumentResolver());
WebMvcConfigurer.super.addArgumentResolvers(resolvers);
}

具体实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.pibigstar.springboot.config;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.thymeleaf.util.StringUtils;

import com.pibigstar.springboot.domain.User;
import com.pibigstar.springboot.service.UserService;
import com.pibigstar.springboot.service.impl.UserServiceImpl;
/**
* 拿到session或parameter中的token
* 通过token拿到redis中的user
* 将user注入到方法的参数中
* @author pibigstar
*
*/
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver{

@Autowired
private UserService userService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> parameterType = parameter.getParameterType();
return parameterType==User.class;
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

String cookieToken = getCookieToken(request,UserServiceImpl.COOKIE_USER_TOKEN);
String parameterToken = request.getParameter(UserServiceImpl.COOKIE_USER_TOKEN);

if (StringUtils.isEmpty(parameterToken) && StringUtils.isEmpty(cookieToken)) {
return null;
}
String token = StringUtils.isEmpty(parameterToken)?cookieToken:parameterToken;

return userService.getByToken(response,token);
}

private String getCookieToken(HttpServletRequest request,String cookieName) {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals(cookieName)) {
return cookie.getValue();
}
}
return null;
}

}

4. 使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pibigstar.springboot.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

import com.pibigstar.springboot.domain.User;

@Controller
public class UserController {

/**
* 这里的user 是通过token从redis拿到的
* 具体实现在UserArgumentResolver中
*/
public String index(User user,Model model) {
if(user==null) {
return "login";
}else {
model.addAttribute("user",user);
return "index";
}
}
}

获取微信公众号信息接口

发表于 2019-08-05 | 分类于 随笔小记

西瓜插件里面的一个小接口:

1
https://chromepluginapi.xiguaji.com/InspireCenter/SearchSubscribePopNew?kw=java派大星

kw为公众号名称

Windows下编译Proto文件

发表于 2019-07-31 | 分类于 go

此处借助的为Windows的Linux子系统进行编译的

1. 安装Windows子系统(WSL)

  1. 设置开启开发者模式
  2. 程序中开启WSL子系统
    在这里插入图片描述
  3. 应用商店下载Ubuntu

注意
1 装好之后要修改一次密码,不然无法使用root

1
sudo passwd

2 更新系统

1
sudo apt-get update

3 安装make

1
sudo apt-get install make

4 安装dos2unix

1
sudo apt-get install dos2unix

2.配置编译环境

  1. 安装go
    百度 Ubuntu安装go

  2. 配置go环境
    编辑 /etc/profile 文件

    1
    vim /etc/profile

将下面内容加入到末尾(GOPAT是我Windows中的GOPATH)

1
2
3
4
export GOROOT=/usr/local/go
export GOPATH=/mnt/f/goWork
export PATH=$GOPATH/bin:$PATH
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

执行下面命令使配置生效

1
source /etc/profile

如果出现每次关闭Terminal,配置就会失效,那么将配置放到 /etc/bash.bashrc 文件中

  1. 安装protoc
    去这个网址下载:https://github.com/protocolbuffers/protobuf/releases
    解压:
    1
    unzip protoc.zip

将bin文件夹下的 protoc 复制到Linux 中的 /bin目录下

1
sudo cp protoc/bin/protoc /bin/protoc

执行 protoc -verson 如果输出版本信息则证明配置成功

  1. 安装protoc-gen-go

    1
    go get -u github.com/golang/protobuf/protoc-gen-go
  2. protoc-gen-validate

    1
    go get -d -u github.com/envoyproxy/protoc-gen-validate

然后进行到这个项目的目录

1
2
cd $GOPATH/src/github.com/envoyproxy/protoc-gen-validate
make build

简单谈谈Java中的垃圾回收器

发表于 2019-07-31 | 分类于 Java,面试,JVM

1. 垃圾回收器算法

目前主流垃圾回收器都采用的是可达性分析算法来判断对象是否已经存活,不使用引用计数算法判断对象存活的原因在于该算法很难解决相互引用的问题。

1.1 标记-清除算法(Mark-Sweep)

标记-清除算法由标记阶段和清除阶段构成。标记阶段是把所有活着的对象都做上标记的阶段;清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用。

从标记-清除算法我们可以看出,该算法不涉及对象移动,但是可能会产生内存碎片化问题。空间碎片太高可能会导致程序运行时需要分配较大内存时候,无法找到足够的连续内存,需要其他垃圾回收帮助回收内存。

1.2 复制算法(Copying)

复制算法内存空间分为两块区域:From、to,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

上面那种复制算法有一半的空间是浪费的。所以在Java新生代把内存区域分为Eden空间、from、to空间3个部分,from和to空间也称为survivor 空间,用于存放未被回收的对象。对象开始都是Eden生成;当回收时,将Eden和from中存活的对象移动到to区域中。

复制算法存在空间浪费的情况,始终都要保持一个Survivor是空闲的,并且在GC的时候要是存活对象大小超过了Survivor中的大小,就需要另外的策略存储存活对象。

目前open JDK新生代回收策略就是采用的复制算法,其中Eden和Survivor的默认配置为8:1

1.3 标记-压缩算法(Mark-Compact)

标记-压缩算法由标记阶段和压缩阶段构成。标记阶段标记-清除算法中的标记阶段完全一样,压缩阶段是让所有存活的对象向一端移动。这样空闲内存都在另外一端,属于连续空间,不存在内存碎片化问题,但是会产生对象移动。

1.4 分代算法(Generational GC)

根据对象的不同生命周期分别管理, JVM 中将对象分为我们熟悉的新生代、老年代和永久代分别管理。这样做的好处就是可以根据不同类型对象进行不同策略的管理,例如新生代中对象更新速度快,就会使用效率较高的复制算法。老年代中内存空间相对分配较大,而且时效性不如新生代强,就会常常使用Mark-Sweep-Compact (标记-清除-压缩)算法。

2. 各个算法的性能比较

标记-清除 复制算法 标记压缩
时间开销 中等 最快 最慢
空间浪费 不存在 存在 不存在
内存碎片化 存在 不存在 不存在
是否移动对象 否 是 是

从表格中我们可以看出,复制算法效率最高,也不存在内存碎片化,但有空间浪费的现象,一般用来处理新生代中的对象
而标记-清除算法和标记压缩算法则主要处理老年代中对象内存分配比较大的,并且时效性不如新生代的

3. 常见的垃圾回收器

3.1 按照处理过程分类:

  • 串行垃圾回收器(Serial Garbage Collector)
  • 并行垃圾回收器(Parallel Garbage Collector)
  • 并发标记扫描垃圾回收器(CMS Garbage Collector)

3.1.1 串行垃圾回收器

回收器名称 使用的算法 作用区域 单/多线程 备注
Serial 复制算法 新生代 单线程 简单高效,不建议使用,Client默认的
Serial Old 标记-压缩 老年代 单线程 能和所有的Young GC搭配使用

3.1.2 并行垃圾回收器

回收器名称 使用的算法 作用区域 单多线程 备注
ParNew 复制算法 新生代 多线程 唯一和CMS搭配的新生代垃圾回收器
Parallel Scavenge 复制算法 新生代 多线程 更关注于吞吐量
ParNew Old 标记整理 老年代 多线程 搭配Parallel Scavenge垃圾回收器

3.1.3 并发标记扫描垃圾回收器

回收器名称 使用的算法 作用区域 单多线程 备注
CMS 标记-清除 老年代 多线程 追求最短的暂时时间

3.2 按照处理的区域分类:

3.2.1 新生代(Young GC)

  • Serial
  • ParNew
  • Parallel Scavenge

    3.2.2 老年代(Old GC)

  • Serial Old
  • ParNew Old
  • CMS

4. 垃圾回收器的选择策略

  1. 客户端程序:Serial + Serial Old;
  2. 吞吐率优先的服务端程序(比如:计算密集型):Parallel Scavenge + Parallel Old;
  3. 响应时间优先的服务端程序:ParNew + CMS。

目前很大一部分的Java应用都集中在互联网的服务器端,这类应用尤其关系服务的响应时间,希望应用暂停时间更短,所以基本上使用的都是 ParNew + CMS

在启动JVM参数加上 -XX:+UseConcMarkSweepGC 这个参数表示对于老年代的回收采用 CMS。

4.1 CMS执行过程

CMS 的回收过程主要分为下面的几个步骤:

  1. 初始标记(Initial Mark)
  2. 并发标记(Concurrent marking)
  3. 并发预清理(Concurrent pre-preclean)
  4. 重新标记(Final Remark)
  5. 并发清理(Concurrent sweep)
  6. 并发重置(Concurrent reset)

SpringBoot自定义配置文件读取

发表于 2019-07-31 | 分类于 springboot

有时候我们把配置都放到application.yml文件里面会造成此文件相当不好管理,所以我们可以有意识的进行拆分,将一些配置放到其他的配置文件里面,那么我们如何加载并使用它呢,其实很简单,直接读取然后放到Properties对象中就OK了,看代码

读取配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.pibgstar.demo.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Properties;

/**
* @author pibigstar
* @desc 加载配置文件
**/
public class ConfigUtil {
private static Logger logger = LoggerFactory.getLogger(ConfigUtil.class);
// 配置文件的路径
private static final String CONFIG_NAME = "conf/config.properties";
private static Properties ps;

public static int getInt(String key) {
String value = getValue(key);
return Integer.parseInt(value);
}

public static String getString(String key) {
String value = getValue(key);
try {
return new String(value.getBytes("iso-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "";
}

private static String getValue(String key) {
if (ps == null) {
init();
}
String value = null;
if (StringUtils.isEmpty(value)) {
value = ps.getProperty(key);
}
logger.info("key:"+key+"----value:"+value);
return value;
}

private static synchronized void init() {
try {
InputStream ras = ConfigUtil.class.getClassLoader().getResourceAsStream(CONFIG_NAME);
ps = new Properties();
ps.load(ras);
} catch (IOException e) {
e.printStackTrace();
}
}

}

配置文件放置

我们将config.properties放到resources下新建的conf文件夹下面就OK了

1
2
pibigstar.demo.url=http://www.pibigstar.com
pibigstar.demo.number=8

使用

1
2
3
4
5
6
7
public class TestConfigUtil {
public static void main(String[] args){
String url = ConfigUtil.getString("pibigstar.demo.url");
int number = ConfigUtil.getInt("pibigstar.demo.number");
System.out.println(url + " " + number);
}
}

Mybatis联表查询

发表于 2019-07-31 | 分类于 Java,数据库,mybatis,SpringBoot技能大全

1 使用注解方式

1.1 一对一

ClazzModel.java (返回前端的模型)

1
2
3
4
5
6
7
8
9
10
public class ClazzModel {

private Long id;
private String name;
private String description;
private Grade grade; //联表
private User user;// 联表
//setter、getter

}

ClazzMapper.java

1
2
3
4
5
6
7
8
@Select("select * from poll_clazz")
@Results({
//一对一 one = @One()
@Result(property="id",column="id"),//不加这个查出来的id会为null
@Result(property = "grade",column = "grade_id",one = @One(select="com.pibigstar.dao.GradeMapper.selectByPrimaryKey")),
@Result(property = "user",column = "user_id",one = @One(select="com.pibigstar.dao.UserMapper.selectByPrimaryKey"))
})
List<ClazzModel> findAll();

1.2 一对多

QuestionModel.java

1
2
3
4
5
6
7
8

public class QuestionModel{
private Long id;
private String name;
private String questionType;
private List<Options> options;
//省略 setter、getter方法
}

QuestionMapper.java

1
2
3
4
5
6
7
    @Select("select * from poll_questions")
@Results({
// 一对多 many = @Many()
@Result(property="id",column="id"),//不加这个查出来的id会为null
@Result(property="options",column="id",many=@Many(select="com.pibigstar.dao.OptionsMapper.findAllByQuestionId"))
})
List<QuestionModel> findAll();

1.3 多对多

业务介绍: 有一张问卷表(questionnaire),一张题库表(question),一张问卷与题库的桥表(qq)

希望能查出所有的问卷,每个问卷有对应的题

思路:我们先查出所有的问卷,然后通过问卷id 在桥表中查找出此问卷中的所有问题

QuestionnaireModel.java

1
2
3
4
5
6
7
public class QuestionnaireModel{
private Long id;
private String name;
private String description;
private List<QuestionModel> questions;
//省略setter、getter方法
}

QuestionnaireMapper.java

1
2
3
4
5
6
@Select("select * from poll_questionnaire")
@Results({
@Result(property="id",column="id"),
@Result(property="questions",column="id",many=@Many(select="com.pibigstar.dao.QQMapper.selectAllQuestions")),
})
List<QuestionnaireModel> findAllModel();

QQMapper.java

1
2
3
4
5
6
@Select("select * from poll_questions where id in (select questions_id from poll_qq where questionnaire_id=#{id})")
@Results({
@Result(property="id",column="id"),
@Result(property="options",column="id",many=@Many(select="com.pibigstar.dao.OptionsMapper.findAllByQuestionId"))
})
List<QuestionModel> selectAllQuestions(Long id);

1.4 注意:

分步查询有时候非常浪费数据库资源,我们可以采用懒加载方式,当有需要的时候才进行分步查询
使用:fetchType=FetchType.LAZY

1
2
3
4
5
6
7
8

@Select("select * from poll_clazz")
@Results({
//一对一 one = @One()
@Result(property="id",column="id"),//不加这个查出来的id会为null
@Result(property = "grade",column = "grade_id",one = @One(fetchType=FetchType.LAZY,select="com.pibigstar.dao.GradeMapper.selectByPrimaryKey")),

List<ClazzModel> findAll();

2 使用xml配置方式

2.1 一对一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.briup.apps.poll.dao.extend.ClazzVMMapper">

<resultMap id="clazzVMResultMap" type="com.briup.apps.poll.bean.extend.ClazzVM">
<id column="id" jdbcType="BIGINT" property="id" />
<!-- 联表查询 association -->
<association column="grade_id" property="grade" select="com.briup.apps.poll.dao.GradeMapper.selectByPrimaryKey"></association>
<association column="charge_id" property="charge" select="com.briup.apps.poll.dao.UserMapper.selectByPrimaryKey"></association>
</resultMap>

<select id="selectById" parameterType="java.lang.Long" resultMap="clazzVMResultMap">
select * from poll_clazz where id=#{id};
</select>

</mapper>

2.2 一对多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<resultMap type="com.User" id="userAndItemsResultMap">
<!-- 用户信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 一个用户对应多个订单 -->
<collection property="ordersList" ofType="com.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userid"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<result column="note" property="note"/>
<!-- 一个订单对应多个订单明细 -->
<collection property="orderdetails" ofType="com.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 一个订单明细对应一个商品 -->
<association property="items" javaType="com.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="itemsName"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>

使用java打开网页并截图

发表于 2019-07-31 | 分类于 Java,java工具类

控制浏览器打开网页只适用于JDK1.6之上的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.pibgstar.demo.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
/**
* @author pibigstar
* @desc 网页截图工具类
**/
public class CutPictureUtil {
public static void main(String[] args) throws IOException, URISyntaxException, AWTException {
// 控制浏览器打开网页,仅适用于JdK1.6及以上版本
Desktop.getDesktop().browse(new URL("https://blog.csdn.net/junmoxi").toURI());
Robot robot = new Robot();
// 延迟一秒
robot.delay(1000);
// 获取屏幕宽度和高度
Dimension d = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
int width = (int) d.getWidth();
int height = (int) d.getHeight();
// 最大化浏览器
robot.keyRelease(KeyEvent.VK_F11);
robot.delay(1000);
// 对屏幕进行截图
Image image = robot.createScreenCapture(new Rectangle(0, 0, width, height));
// 通过图形绘制工具类将截图保存
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = img.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
// 保存图片
ImageIO.write(img, "jpg", new File("D:/tmp/"+System.currentTimeMillis()+".jpg"));
System.out.println("done!");
}
}

JS前端随笔小记

发表于 2019-07-20 | 分类于 js

获取点击处附近的值

1
2
3
4
5
6
7
8
<div class="input-group ebs-modal-choose">
<input name="username" value="${item.bidPrice}">
<div class="input-group-addon">
<span class=" btn-default selectPrice">
<i class="epsicons icon-select1"></i>
</span>
</div>
</div>

点击span按钮时获取input中的值

1
2
3
 $(document).on('click', '.selectPrice',function(){
var username= $(this).parent().parent().find("input[name='username']").val();
});

this 对象指的是点击的span标签对象,第一个parent获取到它的父级div对象,再通过parent获取div的父级对象div,在获取此div下面input对象的值。

禁止a标签点击

1
<a class="disable">pibigstar</a>
1
2
3
.disable{
pointer-events:none;
}

输出横竖表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<table id="priceTable" class="table scroll table-bordered" border="1">
<tbody id="priceTbody">
<tr>
<td></td>
<c:forEach items="${srModel.levelInfos}" var="levelInfo">
<td>${levelInfo}</td>
</c:forEach>
</tr>
<c:forEach items="${srModel.itemInfos}" var="itemInfo">
<tr>
<td>${itemInfo}</td>
<c:forEach items="${srModel.levelInfos}" var="levelInfo">
<td>
<input name="price" >
</td>
</c:forEach>
</tr>
</c:forEach>
</tbody>
</table>

遍历数组

1
2
3
4
var content = ["1","2","3"];
$.each(content, function(i,item){
console("下标:"+ i +"值:"+item);
})

对象转JSON

1
2
3
4
5
6
var data = [];
data[0] = new Object();
data[0].id = 1;
data[0].name = "pibigstar";
var str = JSON.stringify(data);
[{"id":"1","name":"pibigstar"}]

新增/删除CSS样式

1
2
$("#itemDiv").removeClass("hidden");
$("#itemDiv").addClass("hidden");

获取点击处在此列表中的位置

1
2
3
 $(document).on('click','.deleteItemBtn',function() {
var currentCell =$("#myUl li").index(this) + 1;
})

程序员开发必备工具(一)之IDEA插件

发表于 2019-07-20 | 分类于 工具使用

@[TOC]

1. 必备的IDEA插件

1.1 mybatiscodehelperpro

mybatis代码自动生成插件,大部分单表操作的代码可自动生成 减少重复劳动 大幅提升效率。同时可在XML和接口间跳转。破解版:下载

1.2 Translation

翻译插件,开发必不可少的

1.3 Maven Helper

检测Maven依赖冲突的

1.4 GsonFormat

根据JSON生成实体类。

1.5 RestfulToolkit

根据URL路径快速定位到方法。快捷键 ctrl + Alt + N

1.6 Alibaba Java Coding Guidelines

阿里巴巴出品的代码风格检查,可以扫描整个项目 找到不规范的地方 并且大部分可以自动修复。

1.7 FindBugs-IDEA

检测代码中可能的bug及不规范的位置,写完代码后检测下 避免低级bug

1.8 SequenceDiagram

根据代码生成时序图

1.9 .NR Null Object

Nullable是空对象的相关操作接口,用于确定对象是否为空,因为在空对象模式中,对象为空会被包装成一个Object,成为Null Object,该对象会对原有对象的所有方法进行空实现。

  • 分析所选类可声明为接口的方法;
  • 抽象出公有接口;
  • 创建空对象,自动实现公有接口;
  • 对部分函数进行可为空声明;

1.10 .ignore

生成各种ignore文件,一键创建git ignore文件的模板,免得自己去写

关注我微信公众号每天获取更多干货。
在这里插入图片描述

网页中QQ常用代码

发表于 2019-07-16 | 分类于 工具使用,随笔小记

@[toc]

1. 点击链接打开会话窗口

1
2
3
4
<a href="http://wpa.qq.com/msgrd?v=3&uin=741047261&site=qq&menu=yes">点击与我联系</a>

<!--下面这个也可以实现 -->
tencent://message/?Menu=yes&uin=741047261&Service=300&sigT=45a1e5847943b64c6ff3990f8a9e644d2b31356cb0b4ac6b24663a3c8dd0f8aa12a595b1714f9d45

2. 点击链接添加好友

1
<a href="tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=741047261&website=www.oicqzone.com">添加好友</a>

3. 点击加群

  1. 进入 https://qun.qq.com/join.html
  2. 选择哪个群
    这里写图片描述
  3. 复制网页代码即可
    1
    <a href="https://shang.qq.com/wpa/qunwpa?idkey=875408aae56499d92ddcdda3966fa7c01e1d3b587b038d335917df7d41893170">点击进群</a>

4. 手机中网页点击链接打开指定会话窗口

1
<a href="mqqwpa://im/chat?chat_type=wpa&uin=5741047261&version=1&src_type=web&web_src=oicqzone.com">点击联系我</a>

5. Android中打开指定QQ会话窗口

1
2
String url="mqqwpa://im/chat?chat_type=wpa&uin=741047261";  
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

6. Android中打开指定应用程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Intent intent = new Intent();
ComponentName cmp = new ComponentName("com.sina.weibo","com.sina.weibo.EditActivity");
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(cmp);
startActivityForResult(intent, 0);
/**
另:几个常用的Package命令:
新浪微博(编辑界面):com.sina.weibo com.sina.weibo.EditActivity

腾讯微博(编辑界面):com.tencent.WBlog com.tencent.WBlog.activity.MicroblogInput

微信: com.tencent.mm com.tencent.mm.ui.LauncherUI

QQ: com.tencent.mobileqq com.tencent.mobileqq.activity.HomeActivity
**/

7. 获取QQ头像

  1. http://q1.qlogo.cn/g?b=qq&nk=741047261&s=100
  2. http://q2.qlogo.cn/headimg_dl?dst_uin=741047261&spec=100

nk是你的QQ号,s是尺寸,尺寸对应关系可以看下图

1…345…14
派大星

派大星

137 日志
64 分类
230 标签
GitHub CSDN
© 2019 派大星