2

问题一,出现以下报错

image.png
按照常理来说一般出现 no provide for NgForm报错都是因为没有引入ReactiveFormsModule,但是经过检查也已经引入了相应的模块。
下面是出现报错的代码,去除后没有问题。

 <form thyForm [formGroup]="loginForm" (ngSubmit)="login()" class="mt-3">
              <thy-form-group thyLabelText="Username">
                <input thyInput name="username" [formControlName]="key.username" placeholder="username">
              </thy-form-group>
              <thy-form-group thyLabelText="Password" thyTipsMode="label">
                <input  thyInput type="password" name="password" [formControlName]="key.password"
                       placeholder="password">
              </thy-form-group>
              <ng-template [ngIf]="errorInfo">
                <hr>
                <small class="text-danger">{{ errorInfo }}</small>
              </ng-template>
              <thy-form-group-footer>
                <button class="mr-2" [thyButton]="'primary'" [thyLoading]="saving" thyLoadingText="Login">
                  Sign in
                </button>
                <a>Forgot password?</a>
              </thy-form-group-footer>
            </form>

在引入[formGroup]="loginForm"之前即只是原型的时候并没有发生报错,为了确认是否是引入formGroup时配置上出现问题,只保留fourgroup部分代码,将之前原型部分去除后在此尝试发现没有问题,即改为如下代码:

<form  [formGroup]="loginForm" (ngSubmit)="login()" class="mt-3">
     <input thyInput name="username" [formControlName]="key.username" placeholder="username">
     <input  thyInput type="password" name="password" [formControlName]="key.password"
      placeholder="password">
     <ng-template [ngIf]="errorInfo">
         <hr>
     <small class="text-danger">{{ errorInfo }}</small>
     </ng-template>
     <button class="mr-2" [thyButton]="'primary'" [thyLoading]="saving" thyLoadingText="Login" >
                  Sign in
     </button>
     <a>Forgot password?</a>
</form>

进一步进行测试后可得出结论thyForm不能与formGroup同时使用,即它们之间存在冲突,再次查看thyForm官方文档可发现thyForm是通过ngModel进行绑定的
官方文档示例:

<form thyForm name="demoForm" #demoForm="thyForm">
  <thy-form-group thyLabelText="Username" thyLabelRequired thyTips="This is tips for username">
    <input thyInput name="username" [(ngModel)]="model.name" required placeholder="Please type username" />
  </thy-form-group>
  <thy-form-group thyLabelText="Password" thyLabelRequired thyTips="This is tips for password" thyTipsMode="label">
    <input thyInput type="password" name="password" [(ngModel)]="model.password" required placeholder="Please type password" />
  </thy-form-group>
  <thy-form-group-footer>
    <button [thyButton]="'primary'" [thyLoading]="saving" thyLoadingText="Login" (thyFormSubmit)="login()">
      Login
    </button>
    <button [thyButton]="'link-secondary'" (click)="cancel()">Cancel</button>
  </thy-form-group-footer>
</form>

所以在引入新的写法时首先要做的就是测试和以往常规写法间是否存在冲突

springbootSecurity

Spring Security是spring自带的一个安全管理框架,主要有两个目标——认证和授权。
所需依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

此时当我们启动后台时在运行记录里便可得到登陆默认密码(默认用户名为:user):
图片.png
对于这些我们也可以在application.properties进行自行设定:

spring.security.user.name= liming
spring.security.user.password= liming

此时我们有两种方式进行登陆,一是直接在8080端口进行登陆,二是在前台调用user/login方法,并在后台与其对接。
如果要数据库方式校验用户名密码,可以通过自定义UserDetailsService:
其中 UserDetailsService是springBoot官方给出的接口

public interface UserDetailsService {
  UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

并且在自己的service中实现即可

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    System.out.println("loadUserByUsername");
    User user = this.userRepository.findByUsername(username)
            .orElseThrow(() -> new EntityNotFoundException("用户实体不存在"));
    // 设置用户角色
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();

    return new org.springframework.security.core.userdetails.User(username, "", authorities);
  }

其中的authorities便是官方给出的便于设定用户权限的参数。
比如我们可以像下面这样设置其权限(设置其权限为test):

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    System.out.println("loadUserByUsername");
    User user = this.userRepository.findByUsername(username)
            .orElseThrow(() -> new EntityNotFoundException("用户实体不存在"));
    // 设置用户角色
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
    SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("test");
    authorities.add(simpleGrantedAuthority);

    return new org.springframework.security.core.userdetails.User(username, "", authorities);
  }

然后再在MvcSecurityConfig中进行以下配置即可(表示访问user下的url需要具备test权限):

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            // 开放端口
            .antMatchers("/user/**").access("hasRole('test')")
            .anyRequest().authenticated()
            .   .   . 
}

如果我们给予的权限是test,把上面配置的权限改为test1的话再去访问user下的页面就会像下面这样:
图片.png
然后由于我们目前想要实现的是匹配好用户名即可登陆,无需验证密码,所以要通过BCryptPasswordEncoder进行自定义密码验证。

public class MyBCryptPasswordEncoder extends BCryptPasswordEncoder {
  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  @Override
  public boolean matches(CharSequence rawPassword, String encodedPassword) {
    if (rawPassword == null) {
      throw new IllegalArgumentException("rawPassword cannot be null");
    }
    logger.info("数据库中存在该角色信息,匹配成功");
    return true;
  }
}

其中matches就是官方进行密码验证的函数,我们对其重写即可。
然后我们再对C层进行完善,让其返回验证得出的user即可。

  @GetMapping("/login")
  @JsonView(GetUsersJsonView.class)
  public User login(Principal user) throws JsonProcessingException {
    return this.userRepository.findByUsername(user.getName())
            .orElseThrow(() ->
                    new EntityNotFoundException("未在数据库中找到用户,这可能是当前用户被删除导致的"));
  }

其次要说明的就是执行顺序的问题,起初看到C层函数时就在想,前台不是传给的后台用户名
和密码吗,为什么后台可以用Principal类型接受并且不会报错。

public interface Principal {
  boolean equals(Object var1);

  String toString();

  int hashCode();

  String getName();

  default boolean implies(Subject var1) {
    return var1 == null ? false : var1.getPrincipals().contains(this);
  }
}

可见Principal中并没有用户名或时密码这些项目,于是又经过打点才发现执行顺序是什么,即controller中的内容并不是匹配好路由就直接执行。

问题三:安装markdowm插件使angular支持markdown数据的显示
markdown是一种广泛运用的数据格式,gitlab、钉钉都适配于markdown。

第一步:ngx-markdown
npm install ngx-markdown --save

第二步:在angular.json 中引入对应的css文件和js文件
    "styles": [
              "src/styles.css",
              "node_modules/prismjs/themes/prism-okaidia.css",
              "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
              "node_modules/prismjs/plugins/line-highlight/prism-line-highlight.css",
              "node_modules/katex/dist/katex.min.css"
            ],
            "scripts": [
              "node_modules/marked/lib/marked.js",
              "node_modules/prismjs/prism.js",
              "node_modules/prismjs/components/prism-csharp.min.js",
              "node_modules/prismjs/components/prism-css.min.js",
              "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js",
              "node_modules/prismjs/plugins/line-highlight/prism-line-highlight.js",
              "node_modules/prismjs/components/prism-typescript.min.js",
              "node_modules/emoji-toolkit/lib/js/joypixels.min.js",
              "node_modules/katex/dist/katex.min.js"
            ]

并且分别在app.module和你所使用的组件的moudle如test.module中做如下引用:
app.module:

MarkdownModule.forRoot()

test.module:

MarkdownModule.forRoot()

使用方法:
如下使用即可

<markdown>
   .   .   .
</markdown>

效果:(上图不添加markdown,下图为使用markdown解析后的效果)
image.png
image.png
关于图片的引入:
markdown也有可以引入到angular中的编辑器,即Editor.md,可以实现如下的效果:
image.png
官方地址 https://pandao.github.io/edit...

但是根据所查资料,此编辑器需要将其下载到asset文件夹进行引用,虽然可以像下面这样通过npm进行安装,但是也需要手动将其复制到assets文件夹下,这样就导致了web文件夹体积由原来的1.5M增加到8M左右,不符合所需要求,虽然我也尝试着不用assets文件夹直接从node-modules中进行引用但始终没能成功,再加上网上的资料全是要下载到assets中再进行使用于是就放弃了这种方法。

npm install editor.md


李明
441 声望19 粉丝