2024-08-07

在JavaScript中,可以使用encodeURIencodeURIComponentdecodeURIdecodeURIComponent函数来对URL进行编码和解码。

  1. encodeURI():用于编码整个URI。它不会对特定的字符进行编码:字母、数字、( )*-._~
  2. encodeURIComponent():用于编码URI组件。它会对以下特定的字符进行编码:非字母数字字符、:/?#[]@
  3. decodeURI():用于解码由encodeURI()编码的URI。
  4. decodeURIComponent():用于解码由encodeURIComponent()编码的URI组件。

示例代码:




// 原始URL
let originalURL = "https://www.example.com/?query=Hello World!#Section";
 
// 编码URL
let encodedURL = encodeURI(originalURL);
console.log(encodedURL); // 输出: https://www.example.com/?query=Hello%20World!#Section
 
let encodedURLComponent = encodeURIComponent(originalURL);
console.log(encodedURLComponent); // 输出: https%3A%2F%2Fwww.example.com%2F%3Fquery%3DHello%20World%21%23Section
 
// 解码URL
let decodedURL = decodeURI(encodedURL);
console.log(decodedURL); // 输出: https://www.example.com/?query=Hello World!#Section
 
let decodedURLComponent = decodeURIComponent(encodedURLComponent);
console.log(decodedURLComponent); // 输出: https://www.example.com/?query=Hello World!#Section
2024-08-07

在NestJS中,你可以使用@Transaction()装饰器来处理事务。这个装饰器可以被应用在控制器的方法上,以确保在执行这个方法的时候,所有的数据库操作都会在同一个事务内进行。

以下是一个使用@Transaction()装饰器的例子:




import { Controller, Post, Body, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
import { Transaction } from 'typeorm';
import { YourService } from './your.service';
 
@Controller('your-endpoint')
export class YourController {
  constructor(private readonly yourService: YourService) {}
 
  @Post()
  @UseInterceptors(ClassSerializerInterceptor)
  @Transaction()
  async createItem(@Body() createItemDto: any) {
    const result = await this.yourService.createItem(createItemDto);
    return result;
  }
}

在这个例子中,createItem方法会在一个事务的上下文中被执行。如果方法成功完成,事务将会被自动提交。如果方法抛出任何异常,事务将会被自动回滚。

确保你已经配置了TypeORM,并且你的数据库支持事务。例如,如果你使用的是MySQL,你需要确保你的数据库是InnoDB类型的,因为它支持事务处理。

2024-08-07

在Three.js中,要将一个3D对象居中,并获取其中心点,可以使用以下步骤:

  1. 计算3D对象的包围盒(BoundingBox)。
  2. 获取包围盒的中心点。
  3. 将3D对象的位置设置为中心点位置。

以下是实现这些步骤的示例代码:




// 假设我们有一个3D对象(mesh)
 
// 1. 计算包围盒
const box = new THREE.Box3().setFromObject(mesh);
 
// 2. 获取包围盒中心点
const center = new THREE.Vector3();
box.getCenter(center);
 
// 3. 将对象位置设置为中心点
mesh.position.copy(center);

在这段代码中,我们首先创建了一个THREE.Box3对象,并使用setFromObject方法计算出给定3D对象的包围盒。然后,我们使用getCenter方法从包围盒中获取了中心点,最后将3D对象的位置设置为计算出的中心点。这样,3D对象就会居中在场景中了。

2024-08-07



import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
 
// 设置场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
 
// 添加灯光
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
 
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 0.5).normalize();
scene.add(directionalLight);
 
// 创建地形和材质
const geometry = new THREE.PlaneGeometry(100, 100, 100, 100);
const material = new THREE.MeshPhongMaterial({ color: 0xffffff, depthWrite: false });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
 
// 添加模型
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load('models/scene.gltf', (gltf) => {
  scene.add(gltf.scene);
});
 
// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
 
// 渲染循环
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
 
animate();

这段代码示例展示了如何使用Three.js创建一个基本的3D场景,并加载一个模型和轨道控制器,以便用户可以以第一人称视角探索虚拟环境。代码简洁,注重核心功能的实现,并提供了一个清晰的学习路径。

2024-08-07

解释:

  1. export default: 用于默认导出模块中的单个实例(一个值、对象、函数等)。一个模块只能有一个默认导出。
  2. export const: 用于导出多个实例,这里导出的是常量。
  3. async: 用于声明异步函数,异步函数返回一个Promise对象。
  4. await: 用于等待一个Promise对象解析完成,并获取其返回值。

实例代码:




// mathUtils.js
export default function add(a, b) {
  return a + b;
}
 
export const subtract = (a, b) => a - b;
 
// 使用async/await的异步操作
export async function calculate(a, b) {
  // 假设这是一个异步操作,比如网络请求
  const result = await delayedAdd(a, b);
  return result;
}
 
// 一个返回Promise的异步函数
async function delayedAdd(a, b) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(a + b), 1000);
  });
}
 
// main.js
import add, { subtract, calculate } from './mathUtils.js';
 
async function start() {
  const sum = await add(1, 2);
  const difference = subtract(5, 3);
  const calculatedSum = await calculate(3, 4);
  
  console.log('Sum:', sum);
  console.log('Difference:', difference);
  console.log('Calculated Sum:', calculatedSum);
}
 
start();

在这个例子中,mathUtils.js 文件中定义了一个默认导出的 add 函数和一个导出常量 subtract 函数,以及使用 asyncawaitcalculate 函数。main.js 文件中,我们导入了 mathUtils.js 文件中的所有导出项,并在 start 函数中调用了它们。start 函数是一个异步函数,用来启动和运行其他异步操作。

2024-08-07

在Node.js中使用MySQL时,为了防止SQL注入,你应该使用参数化查询(也称为预处理语句)。这通常是通过使用Node.js的MySQL库,例如mysqlmysql2,来实现的,这些库支持使用?作为参数占位符,然后提供一个包含这些参数的数组或对象。

以下是一个使用mysql库的例子,展示了如何使用参数化查询来防止SQL注入:




const mysql = require('mysql');
 
// 创建数据库连接
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'your_username',
  password: 'your_password',
  database: 'your_database'
});
 
// 打开连接
connection.connect();
 
// 使用参数化查询来防止SQL注入
const userId = 'someUserId';
const safeQuery = 'SELECT * FROM users WHERE id = ?';
 
connection.query(safeQuery, [userId], function(error, results, fields) {
  if (error) throw error;
  // 对结果进行处理
  console.log(results);
});
 
// 关闭连接
connection.end();

在这个例子中,?是一个参数占位符,然后在connection.query调用时,我们提供了一个包含用户ID的数组作为第二个参数。这样,无论用户ID的内容如何,都不会导致SQL注入攻击,因为MySQL会将?替换为提供的值,并确保它被当作值处理,而不是SQL代码的一部分。

2024-08-07

在TypeScript中,数据类型可以帮助开发者更好地理解代码,从而写出更加可维护和可预测的代码。TypeScript是JavaScript的一个超集,并添加了静态类型系统。

以下是TypeScript中的一些基本数据类型:

  1. 布尔类型(Boolean)



let isDone: boolean = false;
  1. 数字类型(Number)



let count: number = 10;
  1. 字符串类型(String)



let name: string = "Alice";
  1. 数组类型(Array)



let list: number[] = [1, 2, 3];
// 或者使用泛型
let list: Array<number> = [1, 2, 3];
  1. 元组类型(Tuple)



// 元组类型允许表示一个已知元素数量和类型的数组
let x: [string, number];
x = ['Hello', 10]; // OK
// x = [10, 'Hello']; // Error
  1. 枚举类型(Enum)



enum Color {
  Red = 1,
  Green = 2,
  Blue = 4
}
 
let colorName: string = Color[3];
console.log(colorName);  // 输出: Green
  1. 任意类型(Any)



let notSure: any = 10;
notSure = "I am not sure";
notSure = false; // 这里可以赋予任何类型的值
  1. 空类型(Void)



function warnUser(): void {
  console.log("This is a warning message");
}
  1. Null 和 Undefined



let u: undefined = undefined;
let n: null = null;

TypeScript 与 JavaScript 一样,不需要显式指定类型,它会在运行时自动进行类型推断。但是,当你需要在编译时进行类型检查或者想要更清晰地表明变量的类型时,使用显式类型注解是有帮助的。

2024-08-07

以下是一个使用Nest.js结合MongoDB和Nodemailer实现定时发送邮件的基本示例。请确保您已经安装了Nest.js CLI并创建了Nest.js项目,同时您的MongoDB数据库正常运行,且您有一个可用的QQ邮箱进行发送邮件。

  1. 安装必要的包:



npm install @nestjs/schedule @nestjs/microservices @nestjs/mongoose nodemailer
  1. 配置邮箱服务,在app.module.ts中:



import { Module } from '@nestjs/common';
import { MailerService } from '@nestjs-modules/mailer';
 
@Module({
  imports: [MailerService.forRoot({
    transport: 'smtps://你的qq邮箱:邮箱密码@smtp.qq.com', // 替换为你的QQ邮箱和密码
    defaults: {
      from: '"你的名字" <你的qq邮箱>', // 替换为你的名字和邮箱
    },
  })],
  providers: [],
})
export class AppModule {}
  1. 创建定时任务,在app.controller.ts中:



import { Controller, Inject } from '@nestjs/common';
import { Cron, Interval } from '@nestjs/schedule';
import { MailerService } from '@nestjs-modules/mailer';
 
@Controller()
export class AppController {
  constructor(
    @Inject(MailerService)
    private readonly mailerService: MailerService,
  ) {}
 
  @Cron('*/10 * * * * *') // 每10秒执行一次
  async handleCron() {
    try {
      console.log('Cron is running');
      const results = await this.mailerService.sendMail({
        to: '收件人邮箱', // 替换为收件人邮箱
        subject: 'Testing Nest.js MailerService ⚡',
        text: 'Using text bodies',
        html: '<b>Using html bodies</b>',
      });
      console.log(results);
    } catch (err) {
      console.error(err);
    }
  }
}
  1. 运行定时任务,在main.ts中启动Nest.js应用:



import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

确保您的邮箱开启了SMTP服务,并且您的QQ邮箱已经设置了授权码,而不是密码。以上代码仅供参考,实际应用时请根据自己的需求进行相应的调整。

2024-08-07

以下是一个简易的JSP和Servlet相结合的计算器示例。假设我们有两个文本框用于输入数字,一个下拉列表用于选择运算符,并有一个按钮来提交表单并显示结果。

JSP页面(calculator.jsp)




<!DOCTYPE html>
<html>
<head>
    <title>简易计算器</title>
</head>
<body>
    <form action="CalculatorServlet" method="POST">
        数字1: <input type="text" name="number1" /><br/>
        数字2: <input type="text" name="number2" /><br/>
        运算符:
        <select name="operator">
            <option value="+">+</option>
            <option value="-">-</option>
            <option value="*">*</option>
            <option value="/">/</option>
        </select><br/>
        <input type="submit" value="计算" />
    </form>
    <br/>
    <% if (request.getAttribute("result") != null) { %>
        结果: <%= request.getAttribute("result") %>
    <% } %>
</body>
</html>

Servlet类(CalculatorServlet.java)




import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class CalculatorServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String number1Str = request.getParameter("number1");
        String number2Str = request.getParameter("number2");
        String operator = request.getParameter("operator");
 
        double number1 = Double.parseDouble(number1Str);
        double number2 = Double.parseDouble(number2Str);
        double result = 0;
 
        switch (operator) {
            case "+":
                result = number1 + number2;
                break;
            case "-":
                result = number1 - number2;
                break;
            case "*":
                result = number1 * number2;
                break;
            case "/":
                if (number2 != 0) {
                    result = number1 / number2;
                } else {
                    response.getWriter().write("除数不能为0");
      
2024-08-07

在Vue 3 + TypeScript 项目中使用Mock.js可以帮助你在开发过程中模拟后端数据,而不用依赖实际的后端接口。以下是一个简单的例子,展示如何在Vue 3项目中使用Mock.js:

  1. 安装Mock.js:



npm install mockjs --save-dev
  1. 在项目中创建一个mock数据文件,例如mock/data.ts



import Mock from 'mockjs'
 
const data = Mock.mock({
  'items|30': [{
    id: '@id',
    name: '@name',
    'age|18-30': 1
  }]
})
 
export default data
  1. 创建一个mock服务器文件,例如mock/index.ts



import Mock from 'mockjs'
import data from './data'
 
Mock.mock('/api/users', 'get', data.items)
  1. main.ts或其他初始化文件中启动Mock服务:



import './mock'
 
// ... Vue 应用的创建和挂载代码
  1. 在组件中使用Mock数据:



<template>
  <div>
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} - {{ user.age }}
      </li>
    </ul>
  </div>
</template>
 
<script lang="ts">
import { defineComponent, onMounted, ref } from 'vue'
import axios from 'axios'
 
export default defineComponent({
  setup() {
    const users = ref<any[]>([])
 
    onMounted(async () => {
      try {
        const response = await axios.get('/api/users')
        users.value = response.data
      } catch (error) {
        console.error('Error fetching users:', error)
      }
    })
 
    return { users }
  }
})
</script>

在这个例子中,我们首先安装了mockjs。然后,我们创建了一个模拟数据文件data.ts,使用Mock.js生成了一些用户数据。在index.ts文件中,我们设置了一个Mock服务器,它监听/api/users路径的GET请求,并返回模拟数据。在Vue组件中,我们使用axios发送GET请求到/api/users,并将返回的数据赋值给组件的users响应式属性,然后在模板中遍历展示用户信息。