在实体类里定义一个数据库不存在的字段
1、在mybatis中定义不存在字段//引入 import org.springframework.data.annotation.Transient; //使用 @Transient private List<AwardGuidelineFile> awardGuidelineFileList;2、在jpa项目中定义不存在字段//引入包 import javax.persistence.Transient; //使用 @Transient protected FsCatalog bsParent;3、在mybatis-plus中定义不存在字段@TableField（exist = "false"） private String name;
1、jvm 内存模型程序计数器 Program Counter Register：记录的是正在执行的虚拟机字节码指令的地址。此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError的区域虚拟机：VM Stack描述的是 JAVA 方法执行的内存模型，每个方法在执行的时候都会创建一个栈帧， 用于存储局部变量表，操作数栈，动态链接，方法接口等信息局部变量表存储了编译期可知的各种基本数据类型、对象引用线程请求的栈深度不够会报 StackOverflowError 异常栈动态扩展的容量不够会报 OutOfMemoryError 异常虚拟机栈是线程隔离的，即每个线程都有自己独立的虚拟机栈本地方法：Native Stack本地方法栈类似于虚拟机栈，只不过本地方法栈使用的是本地方法堆：Heap几乎所有的对象实例都在堆上分配内存2、堆所有的对象实例以及数组都要在堆上分配。堆是垃圾收集器管理的主要区域，也被称为“GC 堆”；也是我们优化最多考虑的地方。 堆可以细分为：1.新生代Eden 空间From Survivor 空间To Survivor 空间2.老年代3.永久代/元空间Java8 以前永久代，受 jvm 管理，java8 以后元空间，直接使用物理内存。因此， 默认情况下，元空间的大小仅受本地内存限制。 垃圾回收从 Java8 开始，HotSpot 已经完全将永久代（Permanent Generation）移除，取而代之的是一 个新的区域—元空间（MetaSpace）3、运行图由于FGC的速度比YGC的速度慢得多，所以JVM的优化也是尽量避免FGC
1.Docker安装Nginx并启动#没有安装的情况下会自动安装，可以指定版本 docker run -p 80:80 --name nginx -d nginx:1.10 #将容器内的配置文件拷贝到当前目录 #别忘了后面的点 docker container cp nginx:/etc/nginx . #修改文件名称并把这个 conf 移动到/mydata/nginx 下 mv nginx conf #终止原容器 docker stop nginx #执行命令删除原容器 docker rm nginx #创建新的 nginx；执行以下命令 docker run -p 80:80 --name nginx \ -v /mydata/nginx/html:/usr/share/nginx/html \ -v /mydata/nginx/logs:/var/log/nginx \ -v /mydata/nginx/conf:/etc/nginx \ -d nginx:1.10 #给 nginx 的 html 下面放的所有资源可以直接访问 drwxr-xr-x. 3 root root 34 Oct 17 07:49 html2.搭建域名访问要求是 ： 访问gulimall.com 能访问到我们自己本机idea中启动的product服务思路：我们通过配置本地的host域名映射我们虚拟机的中的nginx，然后nginx在根据转发规把请求转发回我们自己的idea中的本地服务。前置说明：因为我们的nginx的安装在云服务器上的，本地Host文件解析域名后访问云服务器, 结果请求被拦截虽然可以用谷歌浏览器安装ModHeader插件解决，但是我们在把请求映射到nginx后，在让nginx转发回我们本地的服务是无法完成的，因为云服务器无法ping通我们本地的ip 原因 本地pc属于移动宽带的内网环境，说白了就是cmd下ipconfig里的ip是你电脑宽带运营商的一个大网络（外网）下的一个内网ip，服务器无法主动与内网ip建立连接，连路由都做不到。所以不可能ping通的。可以考虑使用VPN在您的电脑和服务器之间建立VPN连接，这样服务器和您的电脑就能像在同一个内网一样互相访问了2.1配置本地host可以利用SwitchHost配置工具。需要注意的是这个软件要用管理员打开，然后C:\Windows\System32\drivers\etc把hosts的文件权限放开，才能进行修改如下图配置，前面是虚拟机的地址，后面是需要解析的域名2.2配置nginx# 查看我们nginx的总配置文件 [root@ecs-284198 conf]# cat /mydata/nginx/conf/nginx.conf user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; } [root@ecs-284198 conf]# # 当前总文件的最后一行 include /etc/nginx/conf.d/*.conf; 他会加载这个路径下的所有以 .conf结尾的文件作为配置文件，并且在包含到我们的当前的总配置文件中，这样就不会导致一个配置文件很大，所以接下来我们到 conf.d 的目录下新建一个gulimall.conf文件 # cd 到 /mydata/nginx/conf/conf.d/会有一个default.conf，然后我们复制一个default.conf为gulimall.conf [root@ecs-284198 conf.d]# cd /mydata/nginx/conf/conf.d/ [root@ecs-284198 conf.d]# ll total 8 -rw-r--r-- 1 root root 1097 Jan 31 2017 default.conf -rw-r--r-- 1 root root 1065 Apr 28 21:56 gulimall.conf [root@ecs-284198 conf.d]# # 修改后的gulimall.conf 如下 server { listen 80; server_name gulimall.com; #charset koi8-r; #access_log /var/log/nginx/log/host.access.log main; location / { proxy_pass http://192.168.56.1:15000; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # 其中 proxy_pass http://192.168.56.1:15000; 中的IP使我们本地的ip,访问会我们自己本地idea启动的product服务 # 但是这样会有一个问题 如果我们的product服务有多个实列，就不好办了，其实这个proxy_pass http://192.168.56.1:15000应该配置成我们的网卡 gateway， 让gateway负载均衡到我们的服务中去，下一节我们会解决这个问题3.Nginx-搭建域名访问（负载就均衡到网关）3.1修改总nginx的配置文件# 在http 模块中配置 upstream [root@ecs-284198 conf]# cat nginx.conf user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; + upstream gulimall{ + server 192.168.56.1:88; + } include /etc/nginx/conf.d/*.conf; } # 配置文件中upstream 叫上有服务器 然后取了一个名字叫gulimall，然后里面的里面配置的是我们网关的地址，就是以后所有请求我们上游服务器gulimall 的地址都会转发到网关去3.2修改gulimall.conf# 在子配置文件gulimall.conf中，的location 块添加 proxy_set_header Host $host; 表示nginx在转发的时候把host也带上，如果不加，nginx会丢失请求头，host，cookies等信息 把原来请求我们product的服务改成proxy_pass http://gulimall;其中 http://gulimall中的gulimall 就是我们在总配置文件中取的上游服务器的名字， # 整配置文件的意思，就是监听到gulimall域名发送过来的80请求，都会转到上游服务器为gulimall中去，并且带上host信息，而上游服务器又是转发到网关的。 [root@ecs-284198 conf]# cat conf.d/gulimall.conf server { listen 80; server_name gulimall.com; #charset koi8-r; #access_log /var/log/nginx/log/host.access.log main; location / { + proxy_set_header Host $host; + proxy_pass http://gulimall; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }3.3修改gateway服务的yaml配置spring: cloud: gateway: routes: # - id: test_route # uri: https://www.baidu.com # predicates: # - Query=url,baidu # # - id: qq_route # uri: https://www.qq.com # predicates: # - Query=url,qq - id: product_route uri: lb://gulimall-product predicates: - Path=/api/product/**,/hello filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: third_party_route uri: lb://gulimall-third-party predicates: - Path=/api/thirdparty/** filters: - RewritePath=/api/thirdparty/(?<segment>.*),/$\{segment} - id: member_route uri: lb://gulimall-member predicates: - Path=/api/member/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: ware_route uri: lb://gulimall-ware predicates: - Path=/api/ware/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: admin_route uri: lb://renren-fast predicates: - Path=/api/** filters: - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment} # 注意要放最后 - id: gulimall_host_route uri: lb://gulimall-product predicates: - Host=gulimall.com4.简单认识一下Nginx和工作原理5.性能压测-优化-Nginx动静分离由于动态资源和静态资源目前都处于服务端，所以为了减轻服务器压力，我们将js、css、img等静态资源放置在Nginx端，以减轻服务器压力。5.1动静态文件上传到 mydata/nginx/html/static/index/css，这种格式5.2修改index.html的静态资源路径修改index.html的静态资源路径，加上static前缀src=“/static/index/img/img_09.png”5.3修改/mydata/nginx/conf/conf.d/gulimall.conf如果遇到有/static为前缀的请求，转发至html文件夹location /static/ { root /usr/share/nginx/html; } location / { proxy_pass http://gulimall; proxy_set_header Host $host; }
1.引入jar包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>2.后端代码package com.atguigu.gulimall.product.web; import com.atguigu.gulimall.product.entity.CategoryEntity; import com.atguigu.gulimall.product.service.CategoryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; import java.util.Map; @Controller public class IndexController { @Autowired CategoryService categoryService; @GetMapping({"/", "/index.html"}) public String indexPage(Model model) { //1.查出所有的一级分类 List<CategoryEntity> categoryEntities = categoryService.getLevel1Categorys(); model.addAttribute("categorys", categoryEntities); //视图解析器进行拼串 //"classpath:/templates/" +返回值+ ".html" return "index"; } }3.在resource下新建templates文件夹（页面都放进这里面） 谷粒商城2020 X 家用电器 Hi, 欢迎来到! 登录 注册 新人福利 PLUS会员 促销 公告 更多 全民纸巾大作战 家具建材满999减300元 黑科技冰箱，下单立减千元 抢102减101神券！ 关于召回普利司通（天津）轮胎有限公司2个规格乘用车轮胎的公告 物流推出配送员统一外呼电话"95056” 天府大件运营中心开仓公告 大件物流“送装一体”服务全面升级！ 话费 机票 酒店 游戏 企业购 加油卡 电影票 火车票 众筹 理财 礼品卡 白条 话费 机票 酒店 游戏 X 话费充值 流量充值 套餐变更 号码 面值 100元 20元 50元 10元 2元 ￥98.0-￥100.0 快速充值 抢99减50元话费 X 国际机票 国际/港澳 特惠活动 单程 往返 机票查询 当季热门特惠机票 X 国内港澳台 促销活动 酒店查询 订酒店到 X 点卡 QQ 页游 面值 面值 面值 面值 ￥0.00 直充 卡密 快速充值 吃鸡就要快人一步 4.简单语法示例，更多语法参考官网https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html Welcome to our grocery store! 5.修改Thymeleaf的文件后能及时在页面更新，则要关闭缓存spring: thymeleaf: cache: false6.如果resource下的static文件读取不到时，可以加入以下配置或者在pom文件中加入spring: mvc: static-path-pattern: /static/**或者在pom文件中加入以下配置<resources> <resource> <filtering>false</filtering> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> <include>static/**</include> </includes> </resource> </resources>
1.给es中建立索引。product,建立好映射关系PUT product { "mappings": { "properties": { "skuId": { "type": "long" }, "spuId": { "type": "long" }, "skuTitle": { "type": "text", "analyzer": "ik_smart" }, "skuPrice": { "type": "keyword" }, "skuImg": { "type": "keyword", "index": false, "doc_values": false }, "saleCount": { "type": "long" }, "hosStock": { "type": "boolean" }, "hotScore": { "type": "long" }, "brandId": { "type": "long" }, "catelogId": { "type": "long" }, "brandName": { "type": "keyword", "index": false, "doc_values": false }, "brandImg": { "type": "keyword", "index": false, "doc_values": false }, "catelogName": { "type": "keyword", "index": false, "doc_values": false }, "attrs": { "type": "nested", "properties": { "attrId": { "type": "long" }, "attrName": { "type": "keyword", "index": false, "doc_values": false }, "attrValue": { "type": "keyword" } } } } } }2.Service类package com.atguigu.gulimall.lsearch.service; import com.atguigu.common.to.es.SkuEsModel; import java.io.IOException; import java.util.List; public interface ProductSaveService { boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException; }3.ServiceImpl类package com.atguigu.gulimall.lsearch.service.iml; import com.alibaba.fastjson.JSON; import com.atguigu.common.to.es.SkuEsModel; import com.atguigu.gulimall.lsearch.config.GulimallElasticSearchConfig; import com.atguigu.gulimall.lsearch.constant.EsConstant; import com.atguigu.gulimall.lsearch.service.ProductSaveService; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Slf4j @Service("productSaveService") public class ProductSaveServiceImpl implements ProductSaveService { @Autowired RestHighLevelClient restHighLevelClient; @Override public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException { //保存到es //1.给es中建立索引。product,建立好映射关系 //2.给es中保存数据 BulkRequest bulkRequest, RequestOptions options BulkRequest bulkRequest = new BulkRequest(); for (SkuEsModel model : skuEsModels) { //构造保存请求 IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX); indexRequest.id(model.getSkuId().toString()); String s = JSON.toJSONString(model); indexRequest.source(s, XContentType.JSON); bulkRequest.add(indexRequest); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //TODO 如果批量保存错误则需要处理 boolean b = bulk.hasFailures(); List<String> collect = Arrays.stream(bulk.getItems()).map(item -> { return item.getId(); }).collect(Collectors.toList()); log.info("商品上架成功:{}，返回数据:{}", collect,bulk.toString()); return b; } }4.Controller类package com.atguigu.gulimall.lsearch.controller; import com.atguigu.common.exception.BizCodeEnume; import com.atguigu.common.to.es.SkuEsModel; import com.atguigu.common.utils.R; import com.atguigu.gulimall.lsearch.service.ProductSaveService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @Slf4j @RequestMapping("/search/save") @RestController public class ElasticSaveController { @Autowired ProductSaveService productSaveService; @PostMapping("/product") public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) { boolean b = false; try { b = productSaveService.productStatusUp(skuEsModels); } catch (Exception e) { log.error("ElasticSaveController商品商家错误:{}", e); return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage()); } if (!b) { return R.ok(); } else { return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage()); } } }5.BizCodeEnume枚举package com.atguigu.common.exception; /** * @Description: 错误状态码枚举 * @Created: with IntelliJ IDEA. * @author: 夏沫止水 * @createTime: 2020-05-27 17:29 * * 错误码和错误信息定义类 * 1. 错误码定义规则为5为数字 * 2. 前两位表示业务场景，最后三位表示错误码。例如：100001。10:通用 001:系统未知异常 * 3. 维护错误码后需要维护错误描述，将他们定义为枚举形式 * 错误码列表： * 10: 通用 * 001：参数格式校验 * 002：短信验证码频率太高 * 11: 商品 * 12: 订单 * 13: 购物车 * 14: 物流 * 15：用户 **/ public enum BizCodeEnume { UNKNOW_EXCEPTION(10000, "系统未知异常"), VAILD_EXCEPTION(10001, "参数格式校验失败"), TO_MANY_REQUEST(10002, "请求流量过大，请稍后再试"), SMS_CODE_EXCEPTION(10002, "验证码获取频率太高，请稍后再试"), PRODUCT_UP_EXCEPTION(11000, "商品上架异常"), USER_EXIST_EXCEPTION(15001, "存在相同的用户"), PHONE_EXIST_EXCEPTION(15002, "存在相同的手机号"), NO_STOCK_EXCEPTION(21000, "商品库存不足"), LOGINACCT_PASSWORD_EXCEPTION(15003, "账号或密码错误"), ; private Integer code; private String message; BizCodeEnume(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public String getMessage() { return message; } }6.其他测试功能package com.atguigu.gulimall.lsearch; import com.alibaba.fastjson.JSON; import com.atguigu.gulimall.lsearch.config.GulimallElasticSearchConfig; import lombok.Data; import lombok.ToString; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.Avg; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.Map; @SpringBootTest public class GulimallSearchApplicationTests { @Autowired private RestHighLevelClient client; /** * 测试复杂查询功能 */ @Test public void searchDate() throws IOException { //1.创建检索请求 SearchRequest searchRequest = new SearchRequest(); //指定索引 searchRequest.indices("bank"); //指定DSL，检索条件 //SearchSourceBuilder sourceBuilder 封装的条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //1.1构造检索条件 searchSourceBuilder.query(); searchSourceBuilder.from(); searchSourceBuilder.size(); searchSourceBuilder.aggregation(); searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill")); //1.2按照年龄的值分布进行聚合 TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10); searchSourceBuilder.aggregation(ageAgg); //1.3计算平均薪资 TermsAggregationBuilder balanceAvg = AggregationBuilders.terms("balanceAvg").field("balance"); searchSourceBuilder.aggregation(balanceAvg); System.out.println("检索条件" + searchSourceBuilder.toString()); searchRequest.source(searchSourceBuilder); //2.执行检索 SearchResponse searchResponce = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //3.分析结果 System.out.println(searchResponce.toString()); //Map map = JSON.parseObject(searchResponce.toString(), Map.class); 这种方式太麻烦 //3.1获取所有查询到的数据 SearchHits hits = searchResponce.getHits(); SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String sourceAsString = hit.getSourceAsString(); Account account = JSON.parseObject(sourceAsString, Account.class); System.out.println("account" + account); } //3.2获取这次检索到的分析信息 Aggregations aggregations = searchResponce.getAggregations(); Terms ageAgg1 = aggregations.get("ageAgg"); for (Terms.Bucket bucket : ageAgg1.getBuckets()) { String keyAsString = bucket.getKeyAsString(); System.out.println("年龄" + keyAsString + "===>" + bucket.getDocCount()); } Avg balanceAvg1 = aggregations.get("balanceAvg"); System.out.println("平均工资" + balanceAvg1.getValue()); } @ToString @Data static class Account { private int account_number; private int balance; private String firstname; private String lastname; private int age; private String gender; private String address; private String employer; private String email; private String city; private String state; } /** * 测试存储数据到es,保存更新二合一 */ @Test public void indexDate() throws IOException { IndexRequest indexRequest = new IndexRequest("users"); //数据的id indexRequest.id("1"); // indexRequest.source("userName", "youzi", "age", 18); User user = new User(); user.setUserName("Youzi"); user.setAge(28); user.setGender("男"); String jsonString = JSON.toJSONString(user); //要保存的内容 indexRequest.source(jsonString, XContentType.JSON); //执行index操作 IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //提取有用的响应数据 System.out.println(index); } @Data class User { private String userName; private String gender; private int age; } }7.工具类package com.atguigu.gulimall.lsearch.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 1.导入配置 * 2.编写配置,给容器内注入一个RestHighLevelClient */ @Configuration public class GulimallElasticSearchConfig { @Bean public RestHighLevelClient esRestClient() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //第一个参数是ElasticSearch安装机地址，第二个参数是端口，第三个参数是协议"http"或"https" new HttpHost("192.168.56.10", 9200, "http") ) ); return client; } public static final RequestOptions COMMON_OPTIONS; static { RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder(); // builder.addHeader("Authorization", "Bearer " + TOKEN); // builder.setHttpAsyncResponseConsumerFactory( // new HttpAsyncResponseConsumerFactory // .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024)); COMMON_OPTIONS = builder.build(); } }
//Fegin的调用流程 /** 1.构造请求数据，将对象转为JSON * RequestTemplate template = buildTemplateFromArgs,create(argv); * 2.发送请求进行执行《执行成功会解码响应数据): * executeAndDecode(template); * 3.执行请求会有重试机制 * while(true){ * try{ * executeAndDecode(template); * }catch(){ * try{retryer.continueOrpropagate(e);}catch()fthrow ex;) * continue; * } * * } */ //位于ReflectiveFeign.class public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!"equals".equals(method.getName())) { //判断如果是hashCode或是toString方法就不需要远程调用 if ("hashCode".equals(method.getName())) { return this.hashCode(); } else { //这里是个三元运算符 return "toString".equals(method.getName()) ? this.toString() : //这里才是真正的远程调用，接下来步入这个方法 ((MethodHandler)this.dispatch.get(method)).invoke(args); } ... } //SynchronousMethodHandler.class 代码演示 public Object invoke(Object[] argv) throws Throwable { //请求模板，包含请求路径、请求方式、请求体等信息 //默认构造的模板是不包含请求头和请求参数的 RequestTemplate template = this.buildTemplateFromArgs.create(argv); Options options = this.findOptions(argv); //这是一个重试器，Feign组件默认使用Ribbon的重试机制并增加了根据状态码判断重试机制。默认是关闭的。 Retryer retryer = this.retryer.clone(); while(true) { try { //真正的执行方法在这 return this.executeAndDecode(template, options); } catch (RetryableException var9) { RetryableException e = var9; try { retryer.continueOrPropagate(e); } catch (RetryableException var8) { Throwable cause = var8.getCause(); if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) { throw cause; } throw var8; } if (this.logLevel != Level.NONE) { this.logger.logRetry(this.metadata.configKey(), this.logLevel); } } } }
子页面 <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input> <el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree" @node-click="nodeclick" :filter-node-method="filterNode" :highlight-current="true"></el-tree> 父页面 <el-row :gutter="20"> <el-col :span="6"> <category @tree-node-click="treenodeclick"></category> </el-col> <el-col :span="18"> </el-col> </el-row> 总结：父子组件传递数据子组件给父组件传递数据，事件机制；子组件给父组件发送一个事件，携带上数据。this.$emit("事件名",携带的数据...)
1.安装和原服务器一样的环境1.1我用的是CentOS 系统，首先安装系统环境1.2我使用的是宝塔面板，所以宝塔面板也要安装一致（版本不一致也可以用，不过最好用的是一样的，避免出现未知原因引起的错误）2.迁移前做好备案准备分两种情况在同一个服务器厂商的情况下，只需要把网站的文件迁移到新的服务器（网站文件的路径要和旧服务器的一致）。在不同的服务器厂商的情况下，首先要先进行网站的备案，大概七个工作日，所以不要等到旧服务器快要过期才迁移，这样会导致时间上的不充裕，在迁移过程中会使网站暂停运行，剩下的就是把文件从旧服务器上的文件上传到新的服务器（路径要一致）。3.数据库的迁移在旧服务器上怎么安装的数据库，在新服务器上就怎么安装，最好就是版本都是一样的，然后导出旧数据上的表结构和数据，然后在新服务器上导入，要注意的就是数据库名称和密码要和旧数据库的要一致，这样就方便在新的服务器上运行的时候，不用重新修改代码。4.迁移完成迁移结束后，域名解析要换成新服务器的公网IP，会有缓存，并不是一修改好就马上解析上去的，24-72小时内，所以解析成功后要记得有空看看你的网站能否正常运行。PS1.迁移工具在宝塔面板有一个这个工具，我测试了一下，也是可以迁移成功的2.迁移时图床出现的问题我在迁移过程中是没有发现什么问题，主要是我自己的两个图床工具突然就是上传失败了，完全不能用，报错信息是Call to undefined function think\finfo open()，主要是php中的一个拓展没有安装。2.1找到这个2.2在设置里找到fileinfo并安装2.3重新测试
继承Thread类创建线程//总结：重写的是run()方法，而不是start()方法，但是占用了继承的名额，Java中的类是单继承的 public class MyThread extends Thread{ public static void main(String[] args){ MyThread myThread = new MyThread(); //创建并启动线程 myThread.start(); } @Override public void run(){ //重写run方法 System.out.println("Hello"); } }实现Runnable接口创建线程//总结：实现Runnable接口，实现run()方法，使用依然要用到Thread类，这种方式更常用 //第一种写法 public class MyThread implements Runnable { public static void main(String[] args){ Thread thread = new Thread(new MyThread()); //创建并启动线程 thread.start(); } @Override public void run(){ //重写run方法 System.out.println("Hello"); } } //第二种写法 public class MyThread{ public static void main(String[] args){ Thread thread = new Thread(new Runnable(){ public void run(){ //重写run方法 System.out.println("Hello"); } }); //创建并启动线程 thread.start(); } } //第三种写法 public class MyThread implements Runnable { public static void main(String[] args){ Thread thread = new Thread(()->System.out.println("Hello")); thread.start(); } }使用Callable和Future创建线程//总结：与Runnable的区别在于，Callable可以获取返回结果 //实现Callable接口，实现call()方法，要使用Thread和FutureTask配合，这种方式支持拿到异步执行结果 public class MyThread implements Callable<String> { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(new MyThread()); Thread thread = new Thread(futureTask); thread.start(); //此时是获取到的结果 String result = futureTask.get(); System.out.println(result); } @Override public String call() throws Exception { return "Hello"; } }使用线程池例如用Executor框架//总结：实现Callable接口或者实现Runnable接口都可以，由ExecutorService创建线程 public class MyThread implements Runnable { public static void main(String[] args){ // 创建10个数据级的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(10); threadPool.execute(new MyThread()); } @Override public void run(){ System.out.println("Hello"); } }
解决POST、GET请求中文乱码问题解决post请求乱码问题： 在web.xml中配置一个CharacterEncodingFilter过滤器，设置成 utf-8；<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>@RequestMapping(value = "/add", produces = "text/plain;charset=utf-8")get 请求中文参数出现乱码解决方法有两个修改 tomcat 配置文件添加编码与工程编码一致，如下：<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/另外一种方法对参数进行重新编码//ISO8859-1 是 tomcat 默认编码，需要将 tomcat 编码后的内容按 utf-8 编码 String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),“utf-8”)RedisRedis作用内存存储、持久化，放在内存中，断电即失（持久化重要（RDB、AOF））效率高，可以用于告诉缓存发布订阅系统地图信息分析计数器、计数器（浏览量）特性多样的数据类型持久化集群事务基础知识redis默认16个数据库，默认使用第0个，可以使用select进行切换数据库常用命令#查看数据库大小 DBSIZE #查看所有的key KEY * #清空当前数据库 flushdb #清空所有数据库 flushallRedis是单线程的Redis是基于内存操作，所以他的瓶颈在于机器的内存和网络带宽SpringBean的配置详解Bean的实例化配置静态工厂方法实例化Bean实例工厂方法实例化Bean实现FactoryBean规范延迟实例化BeanBean的依赖注入配置依赖注入的两种方式通过Bean的set方法注入<property name="" ref="" /><property name="" value="" />通过构造Bean的方法注入<constructor-arg name="" ref="" /><constructor-arg name="" value="" />ref用于引用其他的Bean的id；value用于注入普通属性值.依赖注入的数据类型有如下三种：普通数据类型，例如：String，int，boolean等，通过value属性指定引用数据类型，例如：UserDaoImpl，DataSource等，通过ref属性指定集合数据类型，例如：List，Map，Properties等Spring 声明式事务无效可能的原因有哪些？答：可能的原因如下：MySQL 使用的是 MyISAM 引擎，而 MyISAM 是不支持事务的；@Transactional 使用在非 public 方法上，@Transactional 注解只能支持 public 级别，其他类型声明的事务不会生效；@Transactional 在同一个类中无事务方法 A() 内部调用有事务方法 B()，那么此时 B() 事物不会生效。Spring 中的 AOP 的底层实现原理是什么？答：Spring AOP 的底层实现原理就是动态代理。Spring AOP 的动态代理有两种实现方式，对于接口使用的是 JDK 自带的动态代理来实现的，而对比非接口使用的是 CGLib 来实现的。Spring 中 Bean 的生命周期答：Spring 中 Bean 的生命周期如下：① 实例化 Bean：对于 BeanFactory 容器，当客户向容器请求一个尚未初始化的 Bean 时，或初始化 Bean 的时候需要注入另一个尚未初始化的依赖时，容器就会调用 createBean 进行实例化。对于 ApplicationContext 容器，当容器启动结束后，通过获取 BeanDefinition 对象中的信息，实例化所有的 Bean；② 设置对象属性（依赖注入）：实例化后的对象被封装在 BeanWrapper 对象中，紧接着 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入；③ 处理 Aware 接口：Spring 会检测该对象是否实现了 xxxAware 接口，并将相关的 xxxAware 实例注入给 Bean：如果这个 Bean 已经实现了 BeanNameAware 接口，会调用它实现的 setBeanName(String BeanId) 方法，此处传递的就是 Spring 配置文件中 Bean 的 id 值；如果这个 Bean 已经实现了 BeanFactoryAware 接口，会调用它实现的 setBeanFactory() 方法，传递的是 Spring 工厂自身；如果这个 Bean 已经实现了 ApplicationContextAware 接口，会调用 setApplicationContext(ApplicationContext) 方法，传入 Spring 上下文；④ BeanPostProcessor：如果想对 Bean 进行一些自定义的处理，那么可以让 Bean 实现了 BeanPostProcessor 接口，那将会调用 postProcessBeforeInitialization(Object obj, String s) 方法；⑤ InitializingBean 与 init-method：如果 Bean 在 Spring 配置文件中配置了 init-method 属性，则会自动调用其配置的初始化方法；⑥ 如果这个 Bean 实现了 BeanPostProcessor 接口，将会调用 postProcessAfterInitialization(Object obj, String s) 方法；由于这个方法是在 Bean 初始化结束时调用的，因而可以被应用于内存或缓存技术；以上几个步骤完成后，Bean 就已经被正确创建了，之后就可以使用这个 Bean 了。⑦ DisposableBean：当 Bean 不再需要时，会经过清理阶段，如果 Bean 实现了 DisposableBean 这个接口，会调用其实现的 destroy() 方法；⑧ destroy-method：最后，如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性，会自动调用其配置的销毁方法。Spring 中都是用到的设计模式答：Spring 中使用的设计模式如下：工厂模式：通过 BeanFactory、ApplicationContext 来创建 bean 都是属于工厂模式；单例、原型模式：创建 bean 对象设置作用域时，就可以声明 Singleton（单例模式）、Prototype（原型模式）；察者模式：Spring 可以定义一下监听，如 ApplicationListener 当某个动作触发时就会发出通知；责任链模式：AOP 拦截器的执行；策略模式：在创建代理类时，如果代理的是接口使用的是 JDK 自身的动态代理，如果不是接口使用的是 CGLIB 实现动态代理。设置 Ehcache 为 MyBatis 的二级缓存直接在 XML 中配置开启 EhcacheCache<mapper namespace="com.interview.repository.ClassesReposirory"> <cache type="org.mybatis.caches.ehcache.EhcacheCache" > <property name="timeToIdleSeconds" value="3600"/> <property name="timeToLiveSeconds" value="3600"/> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache> select * from classes where id = #{id} </mapper>反射的基本使用下来我们通过反射调用类中的某个方法，来学习反射的基本使用。使用反射调用类中的方法，分为三种情况：调用静态方法调用公共方法调用私有方法假设有一个实体类 MyReflect 包含了以上三种方法，代码如下：package com.interview.chapter4; class MyReflect { // 静态方法 public static void staticMd() { System.out.println("Static Method"); } // 公共方法 public void publicMd() { System.out.println("Public Method"); } // 私有方法 private void privateMd() { System.out.println("Private Method"); } }下面分别来看，使用反射如何调用以上三种类型的方法。① 反射调用静态方法Class myClass = Class.forName("com.interview.chapter4.MyReflect"); Method method = myClass.getMethod("staticMd"); method.invoke(myClass);② 反射调用公共方法Class myClass = Class.forName("com.interview.chapter4.MyReflect"); // 创建实例对象（相当于 new ） Object instance = myClass.newInstance(); Method method2 = myClass.getMethod("publicMd"); method2.invoke(instance);③ 反射调用私有方法Class myClass = Class.forName("com.interview.chapter4.MyReflect"); // 创建实例对象（相当于 new ） Object object = myClass.newInstance(); Method method3 = myClass.getDeclaredMethod("privateMd"); method3.setAccessible(true); method3.invoke(object);反射使用总结反射获取调用类可以通过 Class.forName()，反射获取类实例要通过 newInstance()，相当于 new 一个新对象，反射获取方法要通过 getMethod()，获取到类方法之后使用 invoke() 对类方法进行调用。如果是类方法为私有方法的话，则需要通过 setAccessible(true) 来修改方法的访问限制，以上的这些操作就是反射的基本使用。