一. http post 方法传递参数的2种方式
try{
HttpPost httpPost = new HttpPost(url);
StringEntity stringEntity = new StringEntity(param);//param参数,可以为"key1=value1&key2=value2"的一串字符串
stringEntity.setContentType("application/x-www-form-urlencoded");
httpPost.setEntity(stringEntity);
HttpClient client = new DefaultHttpClient();
HttpResponse httpResponse = client.execute(httpPost);
String result = EntityUtils.toString(httpResponse.getEntity(), HTTP.UTF_8);
} catch(IOException e){
}
有的时候我们不想要通过上面的方式来传递参数,因为考虑请求接口时我比较喜欢的方式是直接把key和value连成一串,如"key1=value1&key2=value2"来作为参数,这样http get和post的方法都可以用同样的结构来作为参数,于是http post的方法请求服务器数据时可以用下面的方法来实现.
List<NameValuePair>list = new ArrayList<NameValuePair>();
for (int i = 0; i < keys.length; i++) {
list.add(new BasicNameValuePair(keys[i], values[i]));
}
HttpPost httpRequst = new HttpPost(urlString);
httpRequst.setEntity(new UrlEncodedFormEntity(list,HTTP.UTF_8));
二. SpringBoot整合websocket实现群聊
前言:
这里不做springboot框架搭建步骤,只做具体的实现,代码里有具体注释,所以不做多解释这里。
代码里可能有相关日志的输出用到了slf4j
1. 引入WebSocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 写入WebSocket配置类
@Configuration
public class WebSocketConfig {
//实例化一个Bean对象
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3. 写入WebSocket群聊Controller控制层
@Slf4j
@Component
@ServerEndpoint("/groupChat/{Group_no}/{username}")
public class GroupChatController {
// 保存 组id->组成员 的映射关系 之所以使用ConcurrentHashMap因为这个是线程安全的,里面采用了分段锁而HashMap是线程不安全的
private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();
// 收到消息调用的方法,群成员发送消息
@OnMessage
public void onMessage(@PathParam("Group_no") String Group_no,
@PathParam("username") String username, String message) {
//得到当前群的所有会话,也就是所有用户
List<Session> sessionList = groupMemberInfoMap.get(Group_no);
// 遍历Session集合给每个会话发送文本消息
sessionList.forEach(item -> {
try {
String text = username + ": " + message;
item.getBasicRemote().sendText(text);
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* 建立连接调用的方法,群成员加入
* @param session 会话
* @param Group_no 群id
*/
@OnOpen
public void onOpen(Session session, @PathParam("Group_no") String Group_no) {
//得到当前群的所有会话,也就是所有用户
List<Session> sessionList = groupMemberInfoMap.get(Group_no);
if (sessionList == null) {
sessionList = new ArrayList<>();
groupMemberInfoMap.put(Group_no,sessionList);
}
sessionList.add(session);
log.info("连接建立");
log.info("群号: {}, 群人数: {}", Group_no, sessionList.size());
}
// 关闭连接调用的方法,群成员退出
@OnClose
public void onClose(Session session, @PathParam("Group_no") String Group_no) {
List<Session> sessionList = groupMemberInfoMap.get(Group_no);
sessionList.remove(session);
log.info("连接关闭");
log.info("群号: {}, 群人数: {}", Group_no, sessionList.size());
}
// 传输消息错误调用的方法
@OnError
public void OnError(Throwable error) {
log.info("连接出错:{}",error.getMessage());
}
}
4. 配置文件
# 服务端口
server.port=8080
5. 前端html,注释是全套的,自己一边用一边理解
<!DOCTYPE html>
<html>
<head>
<title>测试WebSocket</title>
</head>
<body>
<div>
</div>
<center>
<div>
<h1>WebSocket群聊</h1>
<input type="text" id="Group_no" placeholder="请输入房间号"/><br>
<input type="text" id="nickname" placeholder="请输入昵称"/><br>
<input type="submit" value="连接" onclick="connect()" /><br>
<textarea rows="3" cols="20" id="content"></textarea><br>
<input type="submit" value="发送" onclick="start()" />
<br>
</div>
<div id="messages"></div>
</center>
<script type="text/javascript">
var webSocket = null;
//收到消息
function onMessage(event) {
document.getElementById('messages').innerHTML
+= '<br />' + event.data;
}
//建立连接
function onOpen(event) {
document.getElementById('messages').innerHTML
= '连接已经建立';
}
//发生错误
function onError(event) {
alert("发生错误");
webSocket = null;
}
//连接关闭
function onClose(event) {
alert("连接关闭");
webSocket = null;
}
//连接
function connect() {
//获取群号
var Group_no = document.getElementById('Group_no').value;
//获取昵称
var nickname = document.getElementById('nickname').value;
//验证非法数据
if (url == '' || nickname == '') {
alert("群号和用户名不能为空");
return;
}
//验证是否已经建立连接
if(webSocket!=null){
alert("已经建立过连接,如需重新建立连接,请自行更改逻辑,或者重新刷新页面");
return;
}
//创建Websocket连接url
var url = 'ws://localhost:8080/groupChat/' + Group_no + '/' + nickname;
//实例化WebSocket
webSocket = new WebSocket(url);
//出现错误
webSocket.onerror = function(event) {
onError(event)
};
//调用创建连接
webSocket.onopen = function(event) {
onOpen(event)
};
//调用收到消息
webSocket.onmessage = function(event) {
onMessage(event)
};
//调用关闭连接
webSocket.onclose = function(event) {
onClose(event)
};
}
//开始发送
function start() {
//获取发送的内容
var text = document.getElementById('content').value;
if(text== ''){
alert("发送内容不允许为空");
return;
}
if(webSocket==null){
alert("请先建立连接");
return;
}
//调用WebSocket发送的方法
webSocket.send(text);
//初始化文本域的内容为空
document.getElementById('content').value = '';
}
</script>
</body>
</html>
原文地址:https://blog.csdn.net/qq_41741884/article/details/103832925
三. springboot跨域请求解决方案+前后端分离跨域问题其他解决方案
简述跨域问题
1. SpringBoot跨域请求
1.1 直接采用SpringBoot的注解@CrossOrigin
Controller层在需要跨域的类或者方法上加上该注解即可。
1.2 处理跨域请求的Configuration
CrossOriginConfig.java
继承WebMvcConfigurerAdapter或者实现WebMvcConfigurer接口
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* AJAX请求跨域
* @author Mr.W
* @time 2018-08-13
*/
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS)
.maxAge(3600);
}
}
1.3 采用过滤器的方式
@Component
public class CORSFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Credentials", "true");
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
response.getWriter().println("ok");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
1.4 方式4
引入maven依赖:
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>RELEASE</version>
</dependency>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* @author JiaweiWu
* @create 2018/3/22.
*/
@Configuration
public class RouteConfiguration {
//这里为支持的请求头,如果有自定义的header字段请自己添加(不知道为什么不能使用*)
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
private static final String ALLOWED_METHODS = "*";
private static final String ALLOWED_ORIGIN = "*";
private static final String ALLOWED_Expose = "*";
private static final String MAX_AGE = "18000L";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
2. 前后分离的跨域问题其他解决方案
2.1 Nginx服务器反向代理
通过反向代理服务器监听同端口,同域名的访问,不同路径映射到不同的地址,比如,在nginx服务器中,监听同一个域名和端口,不同路径转发到客户端和服务器,把不同端口和域名的限制通过反向代理,来解决跨域的问题。
server {
listen 80;
server_name abc.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location /client { #访问客户端路径
proxy_pass http://localhost:81;
proxy_redirect default;
}
location /apis { #访问服务器路径
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass http://localhost:82;
}
}
或者直接在Nginx中进行配置
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
if ($request_method = 'OPTIONS') {
return 204;
}
}
四. oracle排序时把null值放在最后
今天在做项目的时候遇到一个数据排序的问题,当排序字段为空时,空值会排在数字的前面,这样的排序会非常难看,经过一番努力,终于找到原因了。因为ORACLE认为空值是最大的值,所以将SQL语句改为 ...order by ”排序字段" desc nulls last
;
nulls first
:将null排在最前面。
null last
:将null排在最后面。