当前位置: 首页 > wzjs >正文

asp.net 网站开发的技术优势专业网站优化公司

asp.net 网站开发的技术优势,专业网站优化公司,政协网站建设方案,html5网站源码php文章目录 功能背景功能需要前端开发组件选用组件嵌套和参数绑定上传逻辑示例 后端开发接收逻辑解析逻辑省流纯手动实现(不建议) 功能背景 开发一个配置文件解析功能,需要兼容老版本的配置文件。 功能需要 前端:两个配置文件分别…

文章目录

      • 功能背景
      • 功能需要
      • 前端开发
        • 组件选用
        • 组件嵌套和参数绑定
        • 上传逻辑示例
      • 后端开发
        • 接收逻辑
        • 解析逻辑
          • 省流
          • 纯手动实现(不建议)

功能背景

开发一个配置文件解析功能,需要兼容老版本的配置文件。

功能需要

  1. 前端:两个配置文件分别上传
  2. 后端:配置文件解析、分版本匹配、配置文件映射到实体类

前端开发

组件选用

选用element-plus的el-pload组件进行上传控制,核心组件代码为:

<el-uploadv-model:file-list="fileListModel":on-remove="handleRemove":before-remove="beforeRemove":limit="1":on-exceed="handleExceed":auto-upload="false"class="upload-location"accept=".yml,.yaml"
/>

核心参数说明:

属性作用
v-model:file-list绑定上传文件列表
:on-remove文件移除时触发的回调函数,移除文件是组件自发的,此处绑的是你想在触发该逻辑时做的操作
:before-remove文件移除前触发的函数,此处我绑定了一个确认弹框
:limit="1"限制最多上传 1 个文件
:on-exceed超出文件数量限制时的回调,我绑了个提示框
:auto-upload="false"不自动上传,手动触发上传,因为我要一次提交两个不同的配置文件
class="upload-location"设置样式类
accept=".yml,.yaml"限制可上传的文件类型,此处我设置的是yaml类型

组件嵌套和参数绑定

此处我选择以el-upload组件为核心,将涉及的提示操作等封装成一个自定义组件。在父组件中使用两次该子组件,
并通过defineModel 实现父组件和子组件间值的双向绑定。
el-upload需要绑定的类型为UploadFile数组,即

子组件:const fileListModel = defineModel<UploadFile[]>("fileList"); 
父组件:const fileList = ref<any[]>([]);  
绑定:v-model:file-list="fileList"

UploadFile参数为:

export interface UploadFile {uid: number | stringname: stringstatus?: 'ready' | 'uploading' | 'success' | 'fail'size?: numberpercentage?: numberraw?: Fileresponse?: anyurl?: stringtype?: string
}

其中raw为我们需要向后端传递的数据部分。

上传逻辑示例
const formData = new FormData()
//实际需要进行判空,此处只写核心部分
formData.append('file1', fileList1.value[0].raw) 
formData.append('file2', fileList2.value[0].raw) 
axios.post('/api/upload', formData, {headers: {'Content-Type': 'multipart/form-data'}
}).then(res => {console.log('上传成功:', res.data)
}).catch(err => {console.error('上传失败:', err)
})

后端开发

接收逻辑
@PostMapping("/upload")
public R uploadTask(@RequestParam(value = "file1", required = false) MultipartFile file1,@RequestParam(value = "file2", required = true) MultipartFile file2,@RequestParam(value = "groupId", required = true) Integer groupId) {if (file2 == null || groupId == null) {return R.fail("IMPORT_NOT_EXIST_PARAMS");}if (file1 != null) {return paramService.importTaskParams(file1, file2, groupId);} else {return paramService.importTaskParams(file2, groupId);}
}
解析逻辑

单纯的解析yaml文件并映射比较简单,无非将传入的文件内容使用YAMLMapper解析一下,但本任务有一个要求:

  1. 兼容之前的yml配置文件写法

注:
之前的配置文件使用了 Spring Boot 提供的“松散绑定(Relaxed Binding)”机制,这是直接上传yaml文件并解析无法直接办到的,由此延伸出几点需求:

  1. 支持单字符串向数组类型的映射(即支持a,b,c,d写法);
  2. 支持单字符串向枚举类型忽略大小写的映射;
  3. 中划线和驼峰类型双兼容(即既能解析中划线写法的配置文件,又能解析驼峰写法的配置文件)
  4. 16进制单字符向char类型的映射
省流

手动调用 Spring Boot 提供的绑定工具,不必自己实现。

高效实现:

try ( InputStream inputStream = multipartFile.getInputStream()){// 1. 读取 YAML 文件Yaml yaml = new Yaml();//假设没有上层需要排除Map<String, Object> yamlMap = yaml.load(inputStream);// 2. 平铺嵌套结构(嵌套结构必须用)Map<String, Object> flatMap = flattenMap(yamlMap, null);// 3. 构造 PropertySource(Spring Boot Binder 需要它)PropertySource<?> propertySource = new MapPropertySource("customYaml", flatMap);StandardEnvironment env = new StandardEnvironment();env.getPropertySources().addFirst(propertySource);// 4. 使用 Binder 绑定Binder binder = Binder.get(env);return binder.bind("", Bindable.of(YourConfig.class)).orElseThrow(() -> new RuntimeException("Binding failed"));} catch (Exception e) {e.printStackTrace();}

辅助方法:

    // 将嵌套结构扁平化成 "a.b.c" 格式,只有这样才能处理子级别的中划线映射驼峰private Map<String, Object> flattenMap(Map<String, Object> source, String parentKey) {Map<String, Object> result = new HashMap<>();for (Map.Entry<String, Object> entry : source.entrySet()) {String key = (parentKey != null ? parentKey + "." : "") + entry.getKey();Object value = entry.getValue();if (value instanceof Map) {result.putAll(flattenMap((Map<String, Object>) value, key));} else {result.put(key, value);}}return result;}
纯手动实现(不建议)
  • 单字符串向数组类型的映射
    • 重写set方法,使得数组类型属性可接受非数组类型参数。
  • 单字符串向枚举类型忽略大小写的映射
    • 手写模糊获取方法,并在set方法中调用 。
  • 中划线和驼峰类型双兼容
    • 重构映射逻辑,在映射之前加一段处理,即将原本的中划线名字修改为驼峰,这样就可和实体类中的属性实现匹配,具体实现为:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;public class FlexibleObjectMapper extends ObjectMapper {public FlexibleObjectMapper() {// 注册自定义模块用于字段名转换SimpleModule module = new SimpleModule();module.setDeserializerModifier(new BeanDeserializerModifier() {@Overridepublic JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,BeanDescription beanDesc,JsonDeserializer<?> deserializer) {if (deserializer instanceof BeanDeserializer) {return new FlexibleCaseDeserializer((BeanDeserializer) deserializer);}return deserializer;}});this.registerModule(module);}private static class FlexibleCaseDeserializer extends BeanDeserializer {public FlexibleCaseDeserializer(BeanDeserializer base) {super(base);}@Overridepublic Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {//在原逻辑之前加一段处理,即将原本的中划线名字修改为驼峰,这样就可和实体类中的属性实现匹配JsonNode tree = p.getCodec().readTree(p);if (tree.isObject()) {ObjectNode objNode = (ObjectNode) tree;Map<String, JsonNode> newFields = new HashMap<>();objNode.fields().forEachRemaining(entry -> {String fieldName = entry.getKey();String camelCase = toCamelCase(fieldName);newFields.put(camelCase, entry.getValue());});objNode.removeAll();newFields.forEach(objNode::set);JsonParser newParser = objNode.traverse(p.getCodec());newParser.nextToken(); // advance to START_OBJECT//回到原逻辑return super.deserialize(newParser, ctxt);}return super.deserialize(p, ctxt);}private String toCamelCase(String s) {if (!s.contains("_")) return s;StringBuilder sb = new StringBuilder();boolean upper = false;for (char c : s.toCharArray()) {if (c == '_') {upper = true;} else {sb.append(upper ? Character.toUpperCase(c) : c);upper = false;}}return sb.toString();}}
}
  • 16进制单字符向char类型的映射
    • 自定义反序列化逻辑,指定格式字符串向字符的处理。
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;import java.io.IOException;public class CharDeserializer extends JsonDeserializer<Character> {@Overridepublic Character deserialize(JsonParser jsonParser, DeserializationContext context)throws IOException {String text = jsonParser.getText().trim();// 支持 \u 或 u 开头的十六进制 Unicode 字符if (text.startsWith("\\u") || text.startsWith("u")) {text = text.substring(text.indexOf('u') + 1);try {int code = Integer.parseInt(text, 16);return (char) code;} catch (NumberFormatException e) {throw new IOException("Invalid hexadecimal character: " + text);}}throw new IOException("Empty character string");}
}
http://www.dtcms.com/wzjs/309774.html

相关文章:

  • 做企业网站费用抖音seo软件
  • 网站为什么做黄词骗流量12345浏览器
  • 做网站怎么销售友情链接怎么添加
  • 大华建设项目管理有限公司网站今日新闻十大头条内容
  • 中国营销网站大全常见的系统优化软件
  • 做水果网站需要些什么手续长沙网红打卡地
  • 济南网站建设建站搜索量用什么工具查询
  • 做国际网站需要多少钱免费推广的网站
  • 怎么提高seo排名百度seo营销
  • 嘉兴网站建设电话首页百度
  • 湖北省住建厅网站官网现在搜索引擎哪个比百度好用
  • 15年做哪些网站能致富网络营销seo培训
  • 如何设计一个好网站线下推广100种方式
  • 有没有专门做淘宝客的网站免费设计模板网站
  • 包装网站建设价格疫情防控最新信息
  • 移动端购物网站建设怎么做个网站
  • 深圳网站做的好的公司成都今天宣布的最新疫情消息
  • 建设网站的目的和内容seo手机优化软件哪个好用
  • 河南省副厅长广州网站优化公司
  • 北京市建设工程造价管理处网站交换神器
  • 有哪些网站是用php做的网络关键词优化方法
  • dede 如何做视频网站百度风云榜官网
  • python网站入口网络推广整合平台
  • 卢湾区网站建设制作广州市新闻发布
  • 如何做电影网站才不侵权香港旺道旺国际集团
  • 大庆做网站的海淀区seo引擎优化
  • 建筑挂靠十大网站网站视频播放代码
  • 建设企业网站管理的重要性西安做推广优化的公司
  • 个人网站建设的过程百度标注平台怎么加入
  • 通信管理局 网站备案无锡网站排名公司