注册百度地图API
打开控制台 点击创建应用
打开开发文档 选择
引入百度地图API文件
修改AK密钥
初始化地图 添加基本控件
<body>
<div id="container">
<script>
var map = new BMapGL.Map("container"); // 创建地图实例
var point = new BMapGL.Point(116.404, 39.915); // 创建点坐标
map.centerAndZoom(point, 15); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
map.setHeading(64.5); //设置地图旋转角度
map.setTilt(73); //设置地图的倾斜角度
var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
map.addControl(scaleCtrl);
var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
map.addControl(zoomCtrl);
var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
map.addControl(cityCtrl);
</script>
效果图:
netty
maven依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.66.Final</version>
</dependency>
基本格式
练习
private void handleNetty() throws Exception {
EventLoopGroup bossGrop = new NioEventLoopGroup(1);
//workerGrop 用于业务逻辑的处理 默认线程数是cpu核数*2
EventLoopGroup workerGrop = new NioEventLoopGroup();
try {
//bossGrop 用于接收用户请求 1个线程
//构建netty服务的的辅助类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGrop, workerGrop)
.channel(NioServerSocketChannel.class) //指定通道的处理类型 使用的是Nio方式
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//添加自定义的处理器 这里就是上图的pipeline处理器
ch.pipeline().addLast(new MyChannelHander());
}
});//业务逻辑处理
//启动服务,监听定义的端口
ChannelFuture furture = serverBootstrap.bind(8899).sync();
//等待监听关闭的信号,阻塞当前线程 等待客户端的请求
furture.channel().closeFuture().sync();
} finally {
//优雅的关闭服务
bossGrop.shutdownGracefully();
bossGrop.shutdownGracefully();
}
}
实体类 逻辑处理器(练习)
public class MyChannelHander extends SimpleChannelInboundHandler<ByteBuf> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
String msgStr = msg.toString(CharsetUtil.UTF_8);
//向客户端发送请求
ctx.writeAndFlush(Unpooled.copiedBuffer("好的",CharsetUtil.UTF_8));
}
}
Netty编解码器(了解)
部署kafka
1、部署单节点ZooKeeper
#拉取zk镜像
docker pull zookeeper:3.6
#创建容器
docker create --name zk --restart=always -p 2181:2181 zookeeper:3.6
#启动容器
docker start zk
2、部署kafka
下面部署3个节点的kafka服务
#拉取镜像
docker pull bitnami/kafka:2.8.0
#创建kafka容器
docker run -d --network=host --privileged=true \
--name kafka-node1 -p 9092:9092 \
-e KAFKA_BROKER_ID=1 \
-e KAFKA_CFG_ZOOKEEPER_CONNECT=192.168.31.81:2181 \
-e KAFKA_ZOOKEEPER_PROTOCOL=PLAINTEXT \
-e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 \
-e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.31.81:9092 \
-e ALLOW_PLAINTEXT_LISTENER=yes \
-v kafka-node1-data:/bitnami/kafka/data \
-v kafka-node1-config:/bitnami/kafka/config \
bitnami/kafka:2.8.0
docker run -d --network=host --privileged=true \
--name kafka-node2 -p 9093:9092 \
-e KAFKA_BROKER_ID=2 \
-e KAFKA_CFG_ZOOKEEPER_CONNECT=192.168.31.81:2181 \
-e KAFKA_ZOOKEEPER_PROTOCOL=PLAINTEXT \
-e KAFKA_CFG_LISTENERS=PLAINTEXT://:9093 \
-e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.31.81:9093 \
-e ALLOW_PLAINTEXT_LISTENER=yes \
-v kafka-node2-data:/bitnami/kafka/data \
-v kafka-node2-config:/bitnami/kafka/config \
bitnami/kafka:2.8.0
docker run -d --network=host --privileged=true \
--name kafka-node3 -p 9094:9092 \
-e KAFKA_BROKER_ID=3 \
-e KAFKA_CFG_ZOOKEEPER_CONNECT=192.168.31.81:2181 \
-e KAFKA_ZOOKEEPER_PROTOCOL=PLAINTEXT \
-e KAFKA_CFG_LISTENERS=PLAINTEXT://:9094 \
-e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.31.81:9094 \
-e ALLOW_PLAINTEXT_LISTENER=yes \
-v kafka-node3-data:/bitnami/kafka/data \
-v kafka-node3-config:/bitnami/kafka/config \
bitnami/kafka:2.8.0
3、部署kafka manager
#创建容器,指定ZK地址以及端口映射
docker run -d --name kf-manager -p 9000:9000 -e ZK_HOSTS="192.168.31.81:2181" -e APPLICATION_SECRET=itcast sheepkiller/kafka-manager:1.3.1.8
通过http://192.168.31.81:9000/访问即可。
实现地图数据的收集方案
在resources包下创建一个my.settings txt文档
#netty启动监听的端口号 server.port=8899
编写如下类 用于解析setting
创建MyHttpGeoServer类
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
/**
* @
*/
public class MyHttpGeoServer {
public void handleNetty() throws Exception {
EventLoopGroup bossGrop = new NioEventLoopGroup(1);
//workerGrop 用于业务逻辑的处理 默认线程数是cpu核数*2
EventLoopGroup workerGrop = new NioEventLoopGroup();
try {
//bossGrop 用于接收用户请求 1个线程
//构建netty服务的的辅助类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGrop, workerGrop)
.channel(NioServerSocketChannel.class) //指定通道的处理类型 使用的是Nio方式
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new HttpRequestDecoder())//对于http协议的解码器
.addLast(new HttpResponseEncoder()) //对http协议的编码器 用于数据响应
.addLast(new HttpObjectAggregator(1024 * 128)) //将请求的数据 url或请求头中聚合在一起
//前面三个是必须的 后面写自己的处理器
//添加自定义的处理器
.addLast(new Serverhandler());
}
});//业务逻辑处理
int port = ParseSetting.setting.getInt("server.port");
//启动服务,监听定义的端口
ChannelFuture furture = serverBootstrap.bind(port).sync();
//等待监听关闭的信号,阻塞当前线程 等待客户端的请求
furture.channel().closeFuture().sync();
} finally {
//优雅的关闭服务
bossGrop.shutdownGracefully();
bossGrop.shutdownGracefully();
}
}
}
Serverhandler类
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* http web服务器处理器
*
* @
*/
public class Serverhandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
Request request = Request.build(ctx, fullHttpRequest);
request.getLongParam("userId", 0L);
//响应数据
String result = JSONUtil.toJsonStr(MapUtil.builder().put("status", "ok").build());
this.response(ctx, result);
}
private void response(ChannelHandlerContext ctx, String result) {
this.response(ctx, result);
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
httpResponse.content().writeBytes(Unpooled.copiedBuffer(result, CharsetUtil.UTF_8));
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8");
ctx.writeAndFlush(httpResponse)
.addListener(ChannelFutureListener.CLOSE); //http是短连接 响应完成后需要将Channel关闭
}
}
将request类导入到项目中
package com.itheima.reggie.NettyServer;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.handler.codec.http.multipart.*;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.*;
import java.util.Map.Entry;
/**
* Http请求对象
*/
@Slf4j
public class Request {
public static final String METHOD_DELETE = HttpMethod.DELETE.name();
public static final String METHOD_HEAD = HttpMethod.HEAD.name();
public static final String METHOD_GET = HttpMethod.GET.name();
public static final String METHOD_OPTIONS = HttpMethod.OPTIONS.name();
public static final String METHOD_POST = HttpMethod.POST.name();
public static final String METHOD_PUT = HttpMethod.PUT.name();
public static final String METHOD_TRACE = HttpMethod.TRACE.name();
private static final HttpDataFactory HTTP_DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
private FullHttpRequest nettyRequest;
private String path;
private String ip;
private Map<String, String> headers = new HashMap<String, String>();
private Map<String, Object> params = new HashMap<String, Object>();
private Map<String, Cookie> cookies = new HashMap<String, Cookie>();
/**
* 构造
*
* @param ctx ChannelHandlerContext
* @param nettyRequest HttpRequest
*/
private Request(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
this.nettyRequest = nettyRequest;
final String uri = nettyRequest.uri();
this.path = URLUtil.getPath(getUri());
this.putHeadersAndCookies(nettyRequest.headers());
// request URI parameters
this.putParams(new QueryStringDecoder(uri));
if (nettyRequest.method() != HttpMethod.GET) {
HttpPostRequestDecoder decoder = null;
try {
decoder = new HttpPostRequestDecoder(HTTP_DATA_FACTORY, nettyRequest);
this.putParams(decoder);
} finally {
if (null != decoder) {
decoder.destroy();
decoder = null;
}
}
}
// IP
this.putIp(ctx);
}
/**
* @return Netty的HttpRequest
*/
public HttpRequest getNettyRequest() {
return this.nettyRequest;
}
/**
* 获得版本信息
*
* @return 版本
*/
public String getProtocolVersion() {
return nettyRequest.protocolVersion().text();
}
/**
* 获得URI(带参数的路径)
*
* @return URI
*/
public String getUri() {
return nettyRequest.uri();
}
/**
* @return 获得path(不带参数的路径)
*/
public String getPath() {
return path;
}
/**
* 获得Http方法
*
* @return Http method
*/
public String getMethod() {
return nettyRequest.method().name();
}
/**
* 获得IP地址
*
* @return IP地址
*/
public String getIp() {
return ip;
}
/**
* 获得所有头信息
*
* @return 头信息Map
*/
public Map<String, String> getHeaders() {
return headers;
}
/**
* 使用ISO8859_1字符集获得Header内容<br>
* 由于Header中很少有中文,故一般情况下无需转码
*
* @param headerKey 头信息的KEY
* @return 值
*/
public String getHeader(String headerKey) {
return headers.get(headerKey);
}
/**
* @return 是否为普通表单(application/x-www-form-urlencoded)
*/
public boolean isXWwwFormUrlencoded() {
return "application/x-www-form-urlencoded".equals(getHeader("Content-Type"));
}
/**
* 获得指定的Cookie
*
* @param name cookie名
* @return Cookie对象
*/
public Cookie getCookie(String name) {
return cookies.get(name);
}
/**
* @return 获得所有Cookie信息
*/
public Map<String, Cookie> getCookies() {
return this.cookies;
}
/**
* @return 客户浏览器是否为IE
*/
public boolean isIE() {
String userAgent = getHeader("User-Agent");
if (StrUtil.isNotBlank(userAgent)) {
userAgent = userAgent.toUpperCase();
if (userAgent.contains("MSIE") || userAgent.contains("TRIDENT")) {
return true;
}
}
return false;
}
/**
* @param name 参数名
* @return 获得请求参数
*/
public String getParam(String name) {
final Object value = params.get(name);
if (null == value) {
return null;
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}
/**
* @param name 参数名
* @return 获得请求参数
*/
public Object getObjParam(String name) {
return params.get(name);
}
/**
* 获得GET请求参数<br>
* 会根据浏览器类型自动识别GET请求的编码方式从而解码<br>
* charsetOfServlet为null则默认的ISO_8859_1
*
* @param name 参数名
* @param charset 字符集
* @return 获得请求参数
*/
public String getParam(String name, Charset charset) {
if (null == charset) {
charset = Charset.forName(CharsetUtil.ISO_8859_1);
}
String destCharset = CharsetUtil.UTF_8;
if (isIE()) {
// IE浏览器GET请求使用GBK编码
destCharset = CharsetUtil.GBK;
}
String value = getParam(name);
if (METHOD_GET.equalsIgnoreCase(getMethod())) {
value = CharsetUtil.convert(value, charset.toString(), destCharset);
}
return value;
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得请求参数
*/
public String getParam(String name, String defaultValue) {
String param = getParam(name);
return StrUtil.isBlank(param) ? defaultValue : param;
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得Integer类型请求参数
*/
public Integer getIntParam(String name, Integer defaultValue) {
return Convert.toInt(getParam(name), defaultValue);
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得long类型请求参数
*/
public Long getLongParam(String name, Long defaultValue) {
return Convert.toLong(getParam(name), defaultValue);
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得Double类型请求参数
*/
public Double getDoubleParam(String name, Double defaultValue) {
return Convert.toDouble(getParam(name), defaultValue);
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得Float类型请求参数
*/
public Float getFloatParam(String name, Float defaultValue) {
return Convert.toFloat(getParam(name), defaultValue);
}
/**
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得Boolean类型请求参数
*/
public Boolean getBoolParam(String name, Boolean defaultValue) {
return Convert.toBool(getParam(name), defaultValue);
}
/**
* 格式:<br>
* 1、yyyy-MM-dd HH:mm:ss <br>
* 2、yyyy-MM-dd <br>
* 3、HH:mm:ss <br>
*
* @param name 参数名
* @param defaultValue 当客户端未传参的默认值
* @return 获得Date类型请求参数,默认格式:
*/
public Date getDateParam(String name, Date defaultValue) {
String param = getParam(name);
return StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param);
}
/**
* @param name 参数名
* @param format 格式
* @param defaultValue 当客户端未传参的默认值
* @return 获得Date类型请求参数
*/
public Date getDateParam(String name, String format, Date defaultValue) {
String param = getParam(name);
return StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param, format);
}
/**
* 获得请求参数<br>
* 列表类型值,常用于表单中的多选框
*
* @param name 参数名
* @return 数组
*/
@SuppressWarnings("unchecked")
public List<String> getArrayParam(String name) {
Object value = params.get(name);
if (null == value) {
return null;
}
if (value instanceof List) {
return (List<String>) value;
} else if (value instanceof String) {
return StrUtil.split((String) value, ',');
} else {
throw new RuntimeException("Value is not a List type!");
}
}
/**
* 获得所有请求参数
*
* @return Map
*/
public Map<String, Object> getParams() {
return params;
}
/**
* @return 是否为长连接
*/
public boolean isKeepAlive() {
final String connectionHeader = getHeader(HttpHeaderNames.CONNECTION.toString());
// 无论任何版本Connection为close时都关闭连接
if (HttpHeaderValues.CLOSE.toString().equalsIgnoreCase(connectionHeader)) {
return false;
}
// HTTP/1.0只有Connection为Keep-Alive时才会保持连接
if (HttpVersion.HTTP_1_0.text().equals(getProtocolVersion())) {
if (false == HttpHeaderValues.KEEP_ALIVE.toString().equalsIgnoreCase(connectionHeader)) {
return false;
}
}
// HTTP/1.1默认打开Keep-Alive
return true;
}
// --------------------------------------------------------- Protected method start
/**
* 填充参数(GET请求的参数)
*
* @param decoder QueryStringDecoder
*/
protected void putParams(QueryStringDecoder decoder) {
if (null != decoder) {
List<String> valueList;
for (Entry<String, List<String>> entry : decoder.parameters().entrySet()) {
valueList = entry.getValue();
if (null != valueList) {
this.putParam(entry.getKey(), 1 == valueList.size() ? valueList.get(0) : valueList);
}
}
}
}
/**
* 填充参数(POST请求的参数)
*
* @param decoder QueryStringDecoder
*/
protected void putParams(HttpPostRequestDecoder decoder) {
if (null == decoder) {
return;
}
for (InterfaceHttpData data : decoder.getBodyHttpDatas()) {
putParam(data);
}
}
/**
* 填充参数
*
* @param data InterfaceHttpData
*/
protected void putParam(InterfaceHttpData data) {
final HttpDataType dataType = data.getHttpDataType();
if (dataType == HttpDataType.Attribute) {
//普通参数
Attribute attribute = (Attribute) data;
try {
this.putParam(attribute.getName(), attribute.getValue());
} catch (IOException e) {
log.error("putParam error !", e);
}
} else if (dataType == HttpDataType.FileUpload) {
//文件
FileUpload fileUpload = (FileUpload) data;
if (fileUpload.isCompleted()) {
try {
this.putParam(data.getName(), fileUpload.getFile());
} catch (IOException e) {
log.error("Get file param [{}] error!", data.getName(), e);
}
}
}
}
/**
* 填充参数
*
* @param key 参数名
* @param value 参数值
*/
protected void putParam(String key, Object value) {
this.params.put(key, value);
}
/**
* 填充头部信息和Cookie信息
*
* @param headers HttpHeaders
*/
protected void putHeadersAndCookies(HttpHeaders headers) {
for (Entry<String, String> entry : headers) {
this.headers.put(entry.getKey(), entry.getValue());
}
// Cookie
final String cookieString = this.headers.get(HttpHeaderNames.COOKIE.toString());
if (StrUtil.isNotBlank(cookieString)) {
final Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
for (Cookie cookie : cookies) {
this.cookies.put(cookie.name(), cookie);
}
}
}
/**
* 设置客户端IP
*
* @param ctx ChannelHandlerContext
*/
protected void putIp(ChannelHandlerContext ctx) {
String ip = getHeader("X-Forwarded-For");
if (StrUtil.isNotBlank(ip)) {
ip = NetUtil.getMultistageReverseProxyIp(ip);
} else {
final InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
ip = insocket.getAddress().getHostAddress();
}
this.ip = ip;
}
// --------------------------------------------------------- Protected method end
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("\r\nprotocolVersion: ").append(getProtocolVersion()).append("\r\n");
sb.append("uri: ").append(getUri()).append("\r\n");
sb.append("path: ").append(path).append("\r\n");
sb.append("method: ").append(getMethod()).append("\r\n");
sb.append("ip: ").append(ip).append("\r\n");
sb.append("headers:\r\n ");
for (Entry<String, String> entry : headers.entrySet()) {
sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
}
sb.append("params: \r\n");
for (Entry<String, Object> entry : params.entrySet()) {
sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
}
return sb.toString();
}
/**
* 构建Request对象
*
* @param ctx ChannelHandlerContext
* @param nettyRequest Netty的HttpRequest
* @return Request
*/
protected final static Request build(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
return new Request(ctx, nettyRequest);
}
}
Kafka设置
还没学完,再说吧 忙不过来了 有空再更新