新增QQ机器人

恢复酷Q机器人功能
This commit is contained in:
yutou 2020-10-27 17:20:31 +08:00
parent 023008b609
commit 1b21930013
9 changed files with 305 additions and 84 deletions

41
pom.xml
View File

@ -10,18 +10,23 @@
</parent> </parent>
<groupId>com.yutou</groupId> <groupId>com.yutou</groupId>
<artifactId>tools</artifactId> <artifactId>tools</artifactId>
<version>1.0.9.5</version> <version>1.0.10</version>
<name>tools</name> <name>tools</name>
<description>Demo project for Spring Boot</description> <description>Demo project for Spring Boot</description>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<kotlin.version>1.4.10</kotlin.version>
</properties> </properties>
<repositories> <repositories>
<repository> <repository>
<id>jaudiotagger-repository</id> <id>jaudiotagger-repository</id>
<url>https://dl.bintray.com/ijabz/maven</url> <url>https://dl.bintray.com/ijabz/maven</url>
</repository> </repository>
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@ -101,14 +106,48 @@
<artifactId>ealvatag</artifactId> <artifactId>ealvatag</artifactId>
<version>0.4.3</version> <version>0.4.3</version>
</dependency> </dependency>
<dependency>
<groupId>net.mamoe</groupId>
<artifactId>mirai-core-qqandroid</artifactId>
<version>1.3.2</version> <!-- 替换版本为最新版本 -->
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<plugins> <plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin> </plugin>
</plugins> </plugins>
<resources> <resources>
<resource> <resource>

View File

@ -3,27 +3,29 @@ package com.yutou.tools;
import com.yutou.tools.home.nas.MusicController; import com.yutou.tools.home.nas.MusicController;
import com.yutou.tools.utils.APIFilter; import com.yutou.tools.utils.APIFilter;
import com.yutou.tools.utils.MusicTools; import com.yutou.tools.utils.MusicTools;
import com.yutou.tools.utils.QQBotManager;
import com.yutou.tools.utils.RedisTools; import com.yutou.tools.utils.RedisTools;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.io.IOException;
@SpringBootApplication @SpringBootApplication
public class ToolsApplication { public class ToolsApplication {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("当前版本号:1.0.9.5"); System.out.println("当前版本号:1.0.10");
SpringApplication.run(ToolsApplication.class, args); SpringApplication.run(ToolsApplication.class, args);
RedisTools.initRedisPoolSub(); RedisTools.initRedisPoolSub();
if(APIFilter.isDebug) { if (APIFilter.isDebug) {
MusicController.defaultMusicPath="C:\\Users\\admin\\Music\\"; MusicController.defaultMusicPath = "C:\\Users\\admin\\Music\\";
MusicTools.getInstance().setMusicPath("C:\\Users\\admin\\Music\\"); MusicTools.getInstance().setMusicPath("C:\\Users\\admin\\Music\\");
} } else {
else{ MusicController.defaultMusicPath = "/media/yutou/4t/public/音乐";
MusicController.defaultMusicPath="/media/yutou/4t/public/音乐";
MusicTools.getInstance().setMusicPath("/media/yutou/4t/public/音乐"); MusicTools.getInstance().setMusicPath("/media/yutou/4t/public/音乐");
} }
QQBotManager.getInstance();
} }
} }

View File

@ -3,10 +3,15 @@ package com.yutou.tools.home.nas;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.yutou.tools.interfaces.DownloadInterface; import com.yutou.tools.interfaces.DownloadInterface;
import com.yutou.tools.utils.OSSTools; import com.yutou.tools.utils.OSSTools;
import com.yutou.tools.utils.QQBotManager;
import com.yutou.tools.utils.RedisTools; import com.yutou.tools.utils.RedisTools;
import com.yutou.tools.utils.Tools;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import java.io.File; import java.io.File;
@ -14,16 +19,38 @@ import java.util.Base64;
import java.util.UUID; import java.util.UUID;
@Controller @Controller
@RequestMapping("/localhome/bot") @RequestMapping("/qq/bot")
public class QQBot { public class QQBot {
@RequestMapping("test.do")
@ResponseBody
public String test(){
return "123";
}
@RequestMapping("send.do") @RequestMapping("send.do")
@ResponseBody @ResponseBody
public String send(String msg){ public String send(String msg,String imgUrl){
JSONObject json=new JSONObject(); JSONObject json=new JSONObject();
try { try {
boolean ret= RedisTools.set(1,"msg_"+System.currentTimeMillis(),msg); String ret;
if(StringUtils.isEmpty(imgUrl)){
ret= QQBotManager.getInstance().sendMessage(msg);
}else{
Tools.download(imgUrl, new DownloadInterface() {
@Override
public void onDownload(String file) {
super.onDownload(file);
QQBotManager.getInstance().sendMessage(new File(file),msg);
}
@Override
public void onError(Exception e) {
super.onError(e);
QQBotManager.getInstance().sendMessage(imgUrl+"\n"+msg);
}
});
ret="图片下载中";
}
json.put("code",0); json.put("code",0);
json.put("msg",ret); json.put("msg",ret);
}catch (Exception e){ }catch (Exception e){
@ -33,51 +60,25 @@ public class QQBot {
} }
return json.toJSONString(); return json.toJSONString();
} }
@RequestMapping("msg.do") @RequestMapping("sendAndImg.do")
@ResponseBody @ResponseBody
public String botMsg(String msg,String type){ public String botMsg(String msg,@RequestParam("file") MultipartFile file){
System.out.println(type); JSONObject json=new JSONObject();
if(type.trim().equals("download")){ if(file==null){
JSONObject json=JSONObject.parseObject(new String(Base64.getDecoder().decode(msg))); json.put("code",-1);
String url=json.getString("url"); json.put("msg","图片为空");
if(url.endsWith(".apk")){ return json.toJSONString();
String uuid = UUID.randomUUID().toString().replace("-", "").toLowerCase();
Jedis redisTools = RedisTools.getRedis();
redisTools.select(1);
redisTools.setex("downloadApk_" + uuid, RedisTools.TOKEN_TIMEOUT_DEFAULT, msg);
redisTools.close();
String packageName=null;
String version=null;
packageName=RedisTools.get("csj_packageName",1);
version=RedisTools.get("csj_version",1);
if(packageName==null){
packageName="穿山甲包名";
}
if(version==null){
version="穿山甲版本号";
}
RedisTools.set(1, "msg_" + System.currentTimeMillis(), "检测到上传apk请选择处理方式" +
"\n1)生成穿山甲资源包 回复 #csj#"+packageName+"#"+version+"#downloadApk_" + uuid + "" +
"\n2)不处理 (360s后自动取消)" +
"\n输入 *set csj_packageName XXX 可设置默认包名" +
"\n输入 *set csj_version XXX 可设置默认版本号");
}
} }
return "OK~"; String ret;
} try {
@RequestMapping("csj/assets.do") String path = Tools.createFile("qq_image",file, file.getName());
@ResponseBody ret=QQBotManager.getInstance().sendMessage(new File(path),msg);
public String csjAssets(String data,String packagename,String version){ } catch (Exception e) {
new Thread(new Runnable() { e.printStackTrace();
@Override ret=e.getLocalizedMessage();
public void run() { }
String msg = RedisTools.get(data, 1); json.put("code",0);
JSONObject json=JSONObject.parseObject(new String(Base64.getDecoder().decode(msg))); json.put("msg",ret);
json.put("package",packagename); return json.toJSONString();
json.put("version",version);
BotTools.download(json);
}
}).start();
return "ok";
} }
} }

View File

@ -31,10 +31,10 @@ public class APIFilter implements Filter {
@Override @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
/* if(isDebug){ if(isDebug){
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
return; return;
}*/ }
HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletResponse response = (HttpServletResponse) servletResponse;
String token = request.getParameter("token"); String token = request.getParameter("token");

View File

@ -28,6 +28,7 @@ public class ConfigTools {
} }
public static Object load(String type,String key){ public static Object load(String type,String key){
File file=new File(type); File file=new File(type);
System.out.println(type+"配置文件地址:"+file.getAbsolutePath());
String src=readFile(file); String src=readFile(file);
if(src!=null){ if(src!=null){
JSONObject json=JSONObject.parseObject(src); JSONObject json=JSONObject.parseObject(src);
@ -37,7 +38,7 @@ public class ConfigTools {
} }
return json.getOrDefault(key, ""); return json.getOrDefault(key, "");
} }
return null; return "";
} }
public static boolean save(String type,String key,Object data){ public static boolean save(String type,String key,Object data){
File file=new File(type); File file=new File(type);

View File

@ -19,7 +19,7 @@ public class MusicTools {
public static final int FIND_ARTIST = 2; public static final int FIND_ARTIST = 2;
private static MusicTools tools; private static MusicTools tools;
private String musicPath = "C:\\Users\\admin\\Music"; private String musicPath = "/media/yutou/4t/public/音乐";
private final List<MusicData> musicList = new ArrayList<>(); private final List<MusicData> musicList = new ArrayList<>();
private HashMap<String, List<MusicData>> musicMap = new HashMap<String, List<MusicData>>(); private HashMap<String, List<MusicData>> musicMap = new HashMap<String, List<MusicData>>();
private boolean isScan = false; private boolean isScan = false;
@ -51,6 +51,7 @@ public class MusicTools {
} }
System.out.println("执行扫描"); System.out.println("执行扫描");
musicList.clear(); musicList.clear();
musicMap.clear();
new Thread(() -> { new Thread(() -> {
isScan = true; isScan = true;
scan(new File(musicPath)); scan(new File(musicPath));

View File

@ -0,0 +1,125 @@
package com.yutou.tools.utils;
import kotlin.coroutines.CoroutineContext;
import net.mamoe.mirai.Bot;
import net.mamoe.mirai.BotFactoryJvm;
import net.mamoe.mirai.contact.Contact;
import net.mamoe.mirai.event.EventHandler;
import net.mamoe.mirai.event.Events;
import net.mamoe.mirai.event.ListeningStatus;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.message.GroupMessageEvent;
import net.mamoe.mirai.message.MessageReceipt;
import net.mamoe.mirai.message.data.Image;
import net.mamoe.mirai.message.data.MessageChain;
import net.mamoe.mirai.message.data.MessageUtils;
import net.mamoe.mirai.utils.BotConfiguration;
import net.mamoe.mirai.utils.MiraiLogger;
import org.jetbrains.annotations.NotNull;
import java.io.File;
public class QQBotManager {
private static QQBotManager botManager = null;
private Bot bot;
private static final long qqGroup = 891655174L;
private boolean isLogin=false;
private QQBotManager() {
Object isRun = ConfigTools.load(ConfigTools.CONFIG, "qq_bot");
if (isRun != null && (boolean) isRun) {
init();
isLogin=true;
}
}
private void init() {
new Thread(new Runnable() {
@Override
public void run() {
long qq=2476945931L;
String password="zhang34864394";
if(true) {
qq = 3620756944L;
password = "UAs6YBYMyxJU";
}
bot = BotFactoryJvm.newBot(qq, password, new BotConfiguration() {
{
fileBasedDeviceInfo("qq_bot_devices_info.json");
}
});
Events.registerEvents(bot, new MessageListener());
bot.login();
bot.join();
}
}).start();
}
public static QQBotManager getInstance() {
if (botManager == null) {
botManager = new QQBotManager();
}
return botManager;
}
public boolean isLogin(){
return isLogin;
}
private String getNotLoginQQ(){
return "没有登录QQ";
}
public String sendMessage(String text) {
if (bot != null) {
MessageReceipt<Contact> receipt= bot.getGroup(qqGroup).sendMessage(text);
return receipt.toString();
}
return getNotLoginQQ();
}
public String sendMessage(File imageFile, String text) {
if (bot != null) {
Image image = bot.getGroup(qqGroup).uploadImage(imageFile);
MessageChain chain = MessageUtils.newImage(image.getImageId()).plus(text);
MessageReceipt<Contact> receipt=bot.getGroup(qqGroup).sendMessage(chain);
return receipt.toString();
}
return getNotLoginQQ();
}
public static void main(String[] args) {
getInstance();
}
private static class MessageListener extends SimpleListenerHost {
@Override
public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception) {
super.handleException(context, exception);
System.out.println("error: "+exception.getLocalizedMessage());
}
@EventHandler
public ListeningStatus onGroupMessage(GroupMessageEvent event) {
if(event.getGroup().getId()==qqGroup){
String msg=event.getMessage().contentToString();
msg=msg.replace("","!");
switch (msg){
case "!开机":
RedisTools.Consumer.system("openPC",null);
break;
case "!更新IP":
RedisTools.Consumer.system("updateIP",null);
break;
case "!ip":
RedisTools.Consumer.bot("getip");
break;
default:
if(msg.startsWith("!cmd")){
RedisTools.Consumer.system("cmd",msg.replace("!cmd",""));
}
}
}
return ListeningStatus.LISTENING;
}
}
}

View File

@ -204,7 +204,7 @@ public class RedisTools {
} }
private static class Consumer extends JedisPubSub { protected static class Consumer extends JedisPubSub {
@Override @Override
public void onPMessage(String pattern, String channel, String message) { public void onPMessage(String pattern, String channel, String message) {
super.onPMessage(pattern, channel, message); super.onPMessage(pattern, channel, message);
@ -238,7 +238,7 @@ public class RedisTools {
System.out.println("onMessage: channel=" + channel + " msg=" + message); System.out.println("onMessage: channel=" + channel + " msg=" + message);
} }
private void system(String type, String value) { public static void system(String type, String value) {
try { try {
String exec = null; String exec = null;
switch (type) { switch (type) {
@ -265,23 +265,24 @@ public class RedisTools {
private void bot(String value) { public static void bot(String value) {
switch (value) { switch (value) {
case "getip": case "getip":
JSONObject json = JSONObject.parseObject(Tools.get("https://api.asilu.com/ip/")); JSONObject json = JSONObject.parseObject(Tools.get("https://api.asilu.com/ip/"));
String ip = json.getString("ip"); String ip = json.getString("ip");
RedisTools.set(1, "msg_" + System.currentTimeMillis(), "服务器IP:\n" + ip); QQBotManager.getInstance().sendMessage("服务器IP:\n" + ip);
break; break;
} }
} }
} }
public static void processOut(InputStream inputStream) { public static void processOut(InputStream inputStream) {
String tmp, str = "null"; String tmp;
StringBuilder str = new StringBuilder("null");
try { try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
while ((tmp = reader.readLine()) != null) { while ((tmp = reader.readLine()) != null) {
str += tmp + "\n"; str.append(tmp).append("\n");
} }
reader.close(); reader.close();
inputStream.close(); inputStream.close();
@ -289,7 +290,7 @@ public class RedisTools {
e.printStackTrace(); e.printStackTrace();
} }
System.out.println("cmd > " + str); System.out.println("cmd > " + str);
RedisTools.set(1, "msg_" + System.currentTimeMillis(), str); QQBotManager.getInstance().sendMessage(str.toString());
System.out.println("线程结束"); System.out.println("线程结束");
} }
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -7,6 +7,7 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -92,13 +93,62 @@ public class Tools {
int i = inputStream.read(); int i = inputStream.read();
inputStream.close(); inputStream.close();
connection.disconnect(); connection.disconnect();
if (UpdateIp.nas_ip != null) { if (ConfigTools.load(ConfigTools.CONFIG, "model").equals("nas")) {
String url="http://" + UpdateIp.nas_ip + ":8000/localhome/bot/send.do?msg=" + URLEncoder.encode((title + "\n" + msg), "UTF-8") + "&token=zIrsh9TUZP2lfRW753PannG49E7VJvor"; String img = null;
msg = msg.replace("<br/>", "\n");
if (msg.contains("![logo]")) {
try {
img = msg.split("!\\[logo\\]\\(")[1].split("\\)")[0];
msg = msg.replace("![logo](" + img + ")", "");
} catch (Exception e) {
e.printStackTrace();
}
}
if (img == null) {
QQBotManager.getInstance().sendMessage(title + "\n" + msg);
} else {
String finalMsg = msg;
String finalImg = img;
if (QQBotManager.getInstance().isLogin()) {
download(img, new DownloadInterface() {
@Override
public void onDownload(String file) {
super.onDownload(file);
QQBotManager.getInstance().sendMessage(new File(file), title + "\n" + finalMsg);
}
@Override
public void onError(Exception e) {
super.onError(e);
QQBotManager.getInstance().sendMessage(title + "\n" + finalMsg + "\n" + finalImg);
}
});
}
}
} else if (!StringUtils.isEmpty(UpdateIp.nas_ip)) {
String img = null;
msg = msg.replace("<br/>", "\n");
if (msg.contains("![logo]")) {
try {
img = msg.split("!\\[logo\\]\\(")[1].split("\\)")[0];
msg = msg.replace("![logo](" + img + ")", "");
} catch (Exception e) {
e.printStackTrace();
}
}
String url;
if (img == null) {
url = "http://" + UpdateIp.nas_ip + ":8000/qq/bot/send.do?msg=" + URLEncoder.encode((title + "\n" + msg), "UTF-8") + "&token=zIrsh9TUZP2lfRW753PannG49E7VJvor";
} else {
url = "http://" + UpdateIp.nas_ip + ":8000/qq/bot/send.do?msg=" + URLEncoder.encode((title + "\n" + msg), "UTF-8")
+ "&imgUrl=" + img
+ "&token=zIrsh9TUZP2lfRW753PannG49E7VJvor";
}
System.out.println(url); System.out.println(url);
connection = (HttpURLConnection) new URL(url).openConnection(); connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect(); connection.connect();
inputStream=connection.getInputStream(); inputStream = connection.getInputStream();
i=inputStream.read(); i = inputStream.read();
inputStream.close(); inputStream.close();
connection.disconnect(); connection.disconnect();
} }
@ -191,7 +241,7 @@ public class Tools {
public static String get(String url) { public static String get(String url) {
try { try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"); connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
String tmp; String tmp;
@ -239,19 +289,19 @@ public class Tools {
public static void download(String url, DownloadInterface downloadInterface) { public static void download(String url, DownloadInterface downloadInterface) {
try { try {
HttpURLConnection connection= (HttpURLConnection) new URL(url).openConnection(); HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.disconnect(); connection.disconnect();
new File("tmp").mkdirs(); new File("tmp").mkdirs();
File file=new File("tmp"+File.separator+url.trim().split("/")[url.trim().split("/").length-1]); File file = new File("tmp" + File.separator + url.trim().split("/")[url.trim().split("/").length - 1]);
if(file.exists()){ if (file.exists()) {
file.delete(); file.delete();
} }
FileOutputStream outputStream=new FileOutputStream(file); FileOutputStream outputStream = new FileOutputStream(file);
InputStream inputStream=connection.getInputStream(); InputStream inputStream = connection.getInputStream();
byte[] bytes=new byte[4096]; byte[] bytes = new byte[4096];
int len; int len;
while ((len=inputStream.read(bytes))!=-1){ while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes,0,len); outputStream.write(bytes, 0, len);
outputStream.flush(); outputStream.flush();
} }
outputStream.close(); outputStream.close();
@ -265,16 +315,17 @@ public class Tools {
/** /**
* 构造给前端的文件 * 构造给前端的文件
*
* @param file 文件路径 * @param file 文件路径
* @return 前端获取的文件 * @return 前端获取的文件
*/ */
public static ResponseEntity<FileSystemResource> getFile(File file){ public static ResponseEntity<FileSystemResource> getFile(File file) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
try { try {
headers.add("Content-Disposition", "attachment; filename=" +URLEncoder.encode(file.getName(),"UTF-8")); headers.add("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
headers.add("Content-Disposition", "attachment; filename=" +file.getName()); headers.add("Content-Disposition", "attachment; filename=" + file.getName());
} }
headers.add("Pragma", "no-cache"); headers.add("Pragma", "no-cache");
headers.add("Expires", "0"); headers.add("Expires", "0");