1. 文件上传优化
1.1 url优化
说明: 如果需要通过网络虚拟路径访问服务器.则应该按照如下的配置实现.
- 本地磁盘路径: D:\JT-SOFT\images\2020\09\30\a.jpg
- 网络虚拟路径: http://image.jt.com\2020\09\30\a.jpg
-
1.2 编辑pro配置文件
-
1.3 完成属性的动态赋值
-
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;@Service
@PropertySource("classpath:/properties/images.properties") //容器动态加载指定的配置文件
public class FileServiceImpl implements FileService{//由于属性的值后期可能会发生变化,所以应该动态的获取属性数据. 利用pro配置文件
@Value("${image.rootDirPath}")
private String rootDirPath; // = "D:/JT-SOFT/images";
@Value("${image.urlPath}")
private String urlPath; // = "http://image.jt.com";//1.2 准备图片的集合 包含了所有的图片类型.
private static Set<String> imageTypeSet;
static {
imageTypeSet = new HashSet<>();
imageTypeSet.add(".jpg");
imageTypeSet.add(".png");
imageTypeSet.add(".gif");
}
/**
* 完善的校验的过程
* 1. 校验是否为图片
* 2. 校验是否为恶意程序
* 3. 防止文件数量太多,分目录存储.
* 4. 防止文件重名
* 5. 实现文件上传.
* @param uploadFile
* @return
*/
@Override
public ImageVO upload(MultipartFile uploadFile) {
//0.防止有多余的空格 所以先做去空格的处理
rootDirPath.trim();
urlPath.trim();//1.校验图片类型 jpg|png|gif..JPG|PNG....
//1.1 获取当前图片的名称 之后截取其中的类型. abc.jpg
String fileName = uploadFile.getOriginalFilename();
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
//将数据转化为小写
fileType = fileType.toLowerCase();
//1.3 判断图片类型是否正确.
if(!imageTypeSet.contains(fileType)){
//图片类型不匹配
return ImageVO.fail();
}//2.校验是否为恶意程序 根据宽度/高度进行判断
try {
//2.1 利用工具API对象 读取字节信息.获取图片对象类型
BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
//2.2 校验是否有宽度和高度
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if(width==0 || height==0){
return ImageVO.fail();
}//3.分目录存储 yyyy/MM/dd 分隔
//3.1 将时间按照指定的格式要求 转化为字符串.
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
.format(new Date());
//3.2 拼接文件存储的目录对象
String fileDirPath = rootDirPath + dateDir;
File dirFile = new File(fileDirPath);
//3.3 动态创建目录
if(!dirFile.exists()){
dirFile.mkdirs();
}//4.防止文件重名 uuid.jpg 动态拼接
//4.1 动态生成uuid 实现文件名称拼接 名.后缀
String uuid =
UUID.randomUUID().toString().replace("-", "");
String realFileName = uuid + fileType;//5 实现文件上传
//5.1 拼接文件真实路径 dir/文件名称.
String realFilePath = fileDirPath + realFileName;
//5.2 封装对象 实现上传
File realFile = new File(realFilePath);
uploadFile.transferTo(realFile);//实现文件上传成功!!! http://image.jt.com\2020\09\30\a.jpg
String url = urlPath + dateDir + realFileName;
return ImageVO.success(url,width,height);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
}
}
-
2 反向代理机制说明
2.1 为什么需要反向代理
需求:当完成文件上传时,业务返回页面的是虚拟地址路径
url地址:http://image.jt.com/2020/09/30/a.jpg
真实图片地址:file:///D:/JT-SOFT/image/2020/09/30/d534bed912c748b0ac979ee40222490a.jpg
问题: 如何让用户通过url访问 找到真实的磁盘地址的图片. -
2.2 反向代理机制
2.2.1 反向代理介绍
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。
概括:
1.位于用户(客户端)-服务器之间.
2.用户访问反向代理服务器,以为是真实的服务器信息.
3.用户根本不清楚真实的服务器信息到底是谁.
4.一般反向代理机制保护了真实的服务器信息,所以也称之为服务器端代理. -
2.3 正向代理机制
2.3.1 需求引入
1.宽带: 电信运营商 账号/密码 只能被一台机器使用.
2.路由器: 在家庭的内部创建了局域网 使得局域网中的设备可以通过路由器的功能与外界通信.2.3.2 正向代理介绍
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
总结:
1.正向代理位于客户与服务器之间
2.客户端在发起请求之前 确定了目标服务器的地址.
3.服务器不清楚到底是哪台客户端访问的我,以为只是路由器访问的.
4.正向代理保护了客户的信息,所以也称之为 客户端代理 -
.4 Nginx
2.4.1 Nginx介绍
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。
**Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,**在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。特点:
1.内存少 不超过2M tomcat服务器大约占用600M
2.并发能力强 3-5万次/秒 tomcat服务器大约 150-220之间 -
-
1. 不要将nginx放到C盘及系统目录中 注意中文路径和空格.
2. nginx服务器启动的速度特别快, 窗口会闪退 只启动一次即可
3. nginx启动会占用80端口.
4. nginx命令的运行必须在nginx.exe所在的目录中执行. -
2.4.2 Nginx命令
1).启动命令 start nginx
2).重启命令 nginx -s reload
3).停止命令 nginx -s stop2.4.3 Nginx服务器启动项说明
-
- 2.4.4 关于nginx反向代理说明
http {
# 一个反向代理就是一个server
server {
#监听 80端口
listen 80;
#监听的域名 域名不能重复.
server_name localhost;
#执行的反向代理的动作 / 拦截所有的路径
location / {
# root关键字 代理的是一个目录
root html;
#默认跳转页面
index index.html index.htm;
}
}
}
2.5 Nginx实现图片回显
2.5.1 NGINX配置
# 图片服务器代理 image.jt.com:80
server {
listen 80;
server_name image.jt.com;
location / {
# 转向目录
root D:/JT-SOFT/images;
}
}
2.5.2 修改hosts文件
1.HOSTS文件的说明:
2.HOSTS文件的位置
3).以超级管理员身份运行
# 京淘配置
#左侧写IP地址 右侧写域名 中间使用空格分隔
127.0.0.1 image.jt.com
127.0.0.1 manage.jt.com
#实现 nginx的
#192.168.126.129 image.jt.com
#192.168.126.129 manage.jt.com
127.0.0.1 www.jt.com
#Bug 有时在使用该软件时可能会出现丢失字母的现象.
127.0.0.1 sso.jt.com
3.nginx实现tomcat集群部署
3.1 项目部署
3.2 服务器反向代理
#配置京淘后台管理服务器
# manage.jt.com localhost:8091服务器
server {
listen 80;
server_name manage.jt.com;
location / {
#映射服务器
proxy_pass http://localhost:8091;
}
}
修改nignx服务器之后,重启nginx
3.3 动态获取当前服务器端口号
@RestController
public class PortController {
//从spring服务器中动态的获取端口号
@Value("${server.port}")
private Integer port;
@RequestMapping("/getPort")
public String getPort(){
return "当前服务器访问的端口号:"+port;
}
}
3.4 项目打包
之后从项目的target目录中动态获取jar包文件 准备集群部署.
3.4 项目发布命令
注意事项: 当前的命令执行 会占用dos命令窗口 打印控制台信息. 当dos命令窗口关闭 服务器停止.
退出dos命令窗口: ctrl + c
java: java -jar 8081.war
3.4 nginx负载均衡实现
3.4.1 轮询机制
说明: 按照配置文件的顺序 依次访问服务器.
#配置京淘后台管理服务器
# manage.jt.com localhost:8091服务器
server {
listen 80;
server_name manage.jt.com;
location / {
#映射服务器
#proxy_pass http://localhost:8091;
proxy_pass http://jtWindows;
}
}
# 配置tomcat服务器集群 1.轮询策略
upstream jtWindows {
#server代表服务器地址
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
3.4.2 权重机制
说明: 按照权重的设置,让性能更优的服务器多处理请求.
# 配置tomcat服务器集群 1.轮询策略 2.权重策略
upstream jtWindows {
#server代表服务器地址
server 127.0.0.1:8081 weight=8;
server 127.0.0.1:8082 weight=2;
}
3.4.3 IPHASH策略(了解)
由于某些数据与服务器进行了绑定,则后来必须要求用户访问指定的服务器时,使用IPHASH策略
# 配置tomcat服务器集群 1.轮询策略 2.权重策略 3.iphash策略
upstream jtWindows {
#server代表服务器地址
ip_hash;
server 127.0.0.1:8081 weight=8;
server 127.0.0.1:8082 weight=2;
}
作业
1.安装VMware虚拟机程序
2.检查网卡设置
如果没有网卡 则换一个vmwar版本安装…
3. 启动Linux系统
问题描述:
进入BIOS系统中 开启虚拟化设置即可. 主板系统 开机 F1/F2…
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>jt-sso</artifactId> <!--默认的打包方式就是jar 不写也没有关系--> <packaging>jar</packaging> <parent> <artifactId>jt</artifactId> <groupId>com.jt</groupId> <version>1.0-SNAPSHOT</version> </parent> <!-- 添加依赖信息 --> <dependencies> <dependency> <!--依赖实质依赖的是jar包文件--> <groupId>com.jt</groupId> <artifactId>jt-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <!--3.添加插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
server: port: 8093 servlet: context-path: / spring: datasource: #引入druid数据源 #type: com.alibaba.druid.pool.DruidDataSource #driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true username: root password: root mvc: view: prefix: /WEB-INF/views/ suffix: .jsp #mybatis-plush配置 mybatis-plus: type-aliases-package: com.jt.pojo mapper-locations: classpath:/mybatis/mappers/*.xml configuration: map-underscore-to-camel-case: true logging: level: com.jt.mapper: debug #关于Dubbo配置 dubbo: scan: basePackages: com.jt #指定dubbo的包路径 扫描dubbo注解 application: #应用名称 name: provider-user #一个接口对应一个服务名称 一个接口可以有多个实现 registry: #注册中心 用户获取数据从从机中获取 主机只负责监控整个集群 实现数据同步 address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183 protocol: #指定协议 name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-Service port: 20880 #每一个服务都有自己特定的端口 不能重复.
package com.jt; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.jt.mapper") public class SpringBootRun { public static void main(String[] args) { SpringApplication.run(SpringBootRun.class, args); } }
package com.jt.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.jt.pojo.User; public interface UserMapper extends BaseMapper<User> { }
package com.jt.service; import com.jt.pojo.User; import java.util.List; public interface UserService { List<User> findUserAll(); boolean checkUser(String param, Integer type); }
package com.jt.service; import com.alibaba.dubbo.config.annotation.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.jt.mapper.UserMapper; import com.jt.pojo.User; import com.jt.util.ObjectMapperUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import redis.clients.jedis.JedisCluster; import java.util.UUID; @Service(timeout = 3000) public class DubboUserServiceImpl implements DubboUserService{ @Autowired private UserMapper userMapper; @Autowired private JedisCluster jedisCluster; /** * 注意事项: * 1.暂时使用电话号码代替邮箱 * 2.密码进行md5加密 * 3.入库操作注意事务控制 * @param user */ @Override public void saveUser(User user) { String md5Pass= DigestUtils.md5DigestAsHex(user.getPassword().getBytes()); user.setEmail(user.getPhone()) .setPassword(md5Pass); userMapper.insert(user); } /** * 1.获取用户信息校验数据库中是否又记录 * 2.有 开始执行单点击登陆流程 * 3.没有 直接返回空即可 * * * @param user * @return */ @Override public String doLogin(User user) {//username/password //1.将明文加密 String md5Pass= DigestUtils.md5DigestAsHex(user.getPassword().getBytes()); user.setPassword(md5Pass); QueryWrapper<User> queryWrapper=new QueryWrapper<>(user); //根据对象中不为null的属性当做where条件 User userDB=userMapper.selectOne(queryWrapper); if (userDB==null){ //用户名或者密码错误 return null; }else {//用户名和密码正确 实现单点击登陆操作 String ticket= UUID.randomUUID().toString(); //如果将数据保存到第三方 一般需要脱敏处理 userDB.setPassword("123456你信不?"); String userJSON= ObjectMapperUtil.toJSON(userDB); jedisCluster.setex(ticket, 7*24*60*60, userJSON); return ticket; } } }
package com.jt.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.jt.mapper.UserMapper; import com.jt.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class UserServiceImpl implements UserService{ private static Map<Integer,String> columnMap=new HashMap(); static { columnMap.put(1,"username"); columnMap.put(2,"phone"); columnMap.put(3,"email"); } @Autowired private UserMapper userMapper; @Override public List<User> findUserAll() { return userMapper.selectList(null); } /** * 判断依据:根据用户名查询 如果结果>0用户已存在 * @param param * @param type * @return */ @Override public boolean checkUser(String param, Integer type) { /** * 1.需要将type类型转化为 具体字段信息 * 1=username 2=phone 3=email */ String column=columnMap.get(type); QueryWrapper<User> queryWrapper=new QueryWrapper<>(); queryWrapper.eq(column,param); Integer count=userMapper.selectCount(queryWrapper); return count>0?true:false; } }
package com.jt.controller; import com.fasterxml.jackson.databind.util.JSONPObject; import com.jt.pojo.User; import com.jt.service.UserService; import com.jt.util.CookieUtil; import com.jt.vo.SysResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import redis.clients.jedis.JedisCluster; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.util.List; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Autowired private JedisCluster jedisCluster; /** * 完成测试按钮 * 1.url地址:findUserAll * 2.参数信息:null * 3.返回值结果:List<User> * */ @RequestMapping("/findUserAll") public List<User> findUserAll(){ return userService.findUserAll(); } /** * 业务说明: * jt-web服务器获取jt-sso数据 JSONP跨域请求 * url地址:http://sso.jt.com/user/check/{param}/{type} * 返回值:SysResult对象 * 真实的返回值:callback(SysResult的JSON) */ @RequestMapping("/check/{param}/{type}") public JSONPObject checkUser(@PathVariable String param, @PathVariable Integer type, String callback){ //true表示数据存在 false表示数据可以使用 boolean flag=userService.checkUser(param,type); SysResult.success(flag); return new JSONPObject(callback, SysResult.success(flag)); } /** * 业务实现: * 1.用户通过cookie信息查询用户数据。通过ticket获取redis中的业务数据 * 2.url请求:http://sso.jt.com/user/query/+_ticket * 3.参数: 参数在url中,利用restFul获取 * 4.返回值要求:SysResult对象(userJSON) */ @RequestMapping("/query/{ticket}") public JSONPObject findUserByTicket(@PathVariable String ticket, HttpServletResponse response, String callback){ String userJSON=jedisCluster.get(ticket); /** * 1.lur算法清空数据 * 2.有可能cookie信息有误 * */ if (StringUtils.isEmpty(userJSON)){ //2.应该删除cookie信息 // Cookie cookie=new Cookie("JT_TICKET", ""); // cookie.setMaxAge(0); // cookie.setDomain("jt.com"); // cookie.setPath("/"); // response.addCookie(cookie); CookieUtil.deleteCookie(response, "JT_TICKET", "jt.com"); return new JSONPObject(callback,SysResult.fail()); } return new JSONPObject(callback,SysResult.success(userJSON)); } }